Tarjan缩点
Tarjan缩点用到的思想就是Tarjan求有向图的强连通分量,然后把强连通分量合在一起,就叫缩点;
模板题:
在Tarjan求强连通分量的基础上,加上拓扑排序求DAG的最长路;
代码:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=200010;
const int M=1000100;
const LL mod=100000000;
int dfn[N],low[N],tot,head[N],cnt,n,m,sta[N],top,ans,w[N],fa[N],L[N],R[N];
int dp[N],in[N];
bool vis[N];
struct Node{
int to,nex;
}edge[M];
void add(int p,int q){
edge[cnt].to=q;
edge[cnt].nex=head[p];
head[p]=cnt++;
}
void Tarjan(int p){
dfn[p]=low[p]=++tot;
if(!vis[p]) vis[p]=true,sta[++top]=p;
for(int i=head[p];~i;i=edge[i].nex){
int q=edge[i].to;
if(!dfn[q]){
Tarjan(q);
low[p]=min(low[p],low[q]);
}
else if(vis[q]) low[p]=min(low[p],dfn[q]);
}
if(dfn[p]==low[p]){
fa[p]=p;
vis[p]=false;
while(sta[top]!=p){
vis[sta[top]]=false;
fa[sta[top]]=p;
w[p]+=w[sta[top]];
top--;
}
top--;
}
}
int bfs(){
queue<int>qu;
for(int i=1;i<=n;i++){
if(in[i]==0&&fa[i]==i) qu.push(i),dp[i]=w[i];
}
while(!qu.empty()){
int u=qu.front();
qu.pop();
for(int i=head[u];~i;i=edge[i].nex){
int v=edge[i].to;
dp[v]=max(dp[v],dp[u]+w[v]);
in[v]--;
if(in[v]==0) qu.push(v);
}
}
for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
return ans;
}
int main(){
memset(head,-1,sizeof(head));
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=m;i++){
scanf("%d%d",&L[i],&R[i]);
add(L[i],R[i]);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) Tarjan(i);
}
cnt=0;//重新建边,相当于缩点
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++){
if(fa[L[i]]!=fa[R[i]]){
in[fa[R[i]]]++;
add(fa[L[i]],fa[R[i]]);
}
}
cout<<bfs()<<endl;
return 0;
}