每个强连通分量内部可以自达,可以视为一个点,tarjan跑强连通分量。
重新建边:一条边上的两个点不在一个一个强连通分量里,则将两个强连通分量连边。
可以把原图清空或者重开数组,重开数组的话变量名不要混。
#include<bits/stdc++.h>
using namespace std;
int head[20000],dfn[20000],low[20000],t=0,sta[20000],stac=0,in[20000]
,cnt=0,w[20000],uu[200000],vv[200000],f[20000],color[20000],colornum=0,sum[20000];//u,v是存边,,要开大一点
struct node{
int to,nxt;
}road[200000];
void build(int u,int v)
{
road[++cnt].to=v;
road[cnt].nxt=head[u];
head[u]=cnt;
}
void tarjan(int u)
{
dfn[u]=low[u]=++t;
in[u]=1;sta[++stac]=u;
for(int i=head[u];i;i=road[i].nxt)
{
int v=road[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(in[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
color[u]=++colornum;
sum[colornum]=w[u];
in[u]=0;
while(sta[stac]!=u)
{
color[sta[stac]]=colornum;
sum[colornum]+=w[sta[stac]];
in[sta[stac]]=0;
stac--;//QAQ
}
stac--;
}
}
void dfs(int u)
{
for(int i=head[u];i;i=road[i].nxt)
{
int v=road[i].to;
if(!f[v]) dfs(v);
f[u]=max(f[u],f[v]);//儿子不能回到父亲再去下一个儿子
}
f[u]+=sum[u];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<=m;i++)
{
cin>>uu[i]>>vv[i];
build(uu[i],vv[i]);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
memset(head,0,sizeof(head));
cnt=0;
for(int i=1;i<=m;i++)
if(color[uu[i]]!=color[vv[i]]) build(color[uu[i]],color[vv[i]]);
int ans=0;
for(int i=1;i<=colornum;i++)
{
if(!f[i]) dfs(i);
ans=max(ans,f[i]);
}
cout<<ans;
return 0;
}