传送门(洛谷)
一道模板题
先用Tarjan缩点,在缩点的过程中维护出每个强连通分量的路径值,得出新点,再讲新点建成新图,跑一遍(跑新图)就可以了。没什么难度
Code
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);(i)++)
#define don(i,a,b) for(register int (i)=(a);(i)>=(b);(i)--)
using namespace std;
const int maxn=1e6+10;
int n,m,cnt=0,color,top=0,num=0;
int head[maxn],low[maxn],w[maxn],sum[maxn],de[maxn],st[maxn],dfn[maxn],co[maxn];
int x[maxn],y[maxn],f[maxn];
template <class t> inline void read(t &x)
{
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
x*=f;
}
struct node{
int v,nex;
}e[maxn];
void add(int u,int v)
{
e[++cnt].v=v;
e[cnt].nex=head[u];
head[u]=cnt;
}
void readdata()
{
read(n);read(m);
rep(i,1,n) read(w[i]);
rep(i,1,m) {
read(x[i]);
read(y[i]);
add(x[i],y[i]);
}
}
void Tarjan(int u) {//Tarjan模板
dfn[u]=low[u]=++num;
st[++top]=u;
for(int i=head[u];i;i=e[i].nex) {
int v=e[i].v;
if(!dfn[v]) {
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else {
if(!co[v]) {
low[u]=min(low[u],dfn[v]);
}
}
}
if(low[u]==dfn[u]) {
co[u]=++color;//先染祖先
sum[color]+=w[u];//加上这个强联通的的祖先的值
while(st[top]!=u) {
co[st[top]]=color;//染色,表明已经是一个强联通了
sum[color]+=w[st[top]];//这个强联通分量的每个节点的值
--top;
}
--top;
}
}
void dfs(int x) {//跑新图
if(f[x]) return;
f[x]=sum[x];
int maxsum=0;
for(int i=head[x];i;i=e[i].nex) {
int v=e[i].v;
if(!f[v]) dfs(v);
maxsum=max(maxsum,f[v]);
}
f[x]+=maxsum;
}
void work()
{
cnt=0;
memset(dfn,false,sizeof(dfn));
memset(low,false,sizeof(low));
rep(i,1,n) {
if(!dfn[i]) {
Tarjan(i);
}
}
memset(e,false,sizeof(e));//建新图,没有将head归零害得我调了半个小时
memset(head,false,sizeof(head));
cnt=0;
rep(i,1,m) {
if(co[x[i]]!=co[y[i]]) {//要不是同一个强联通的点才能建图
add(co[x[i]],co[y[i]]);
}
}
int ans=0;
rep(i,1,color) {
// printf("%d %d\n",i,color);
if(!f[i]) {//跑过了就不再跑了
dfs(i);
ans=max(ans,f[i]);
}
}
printf("%d",ans);
}
int main()
{
freopen("input.txt","r",stdin);
readdata();
work();
return 0;
}