洛谷P3387缩点
在tarjan后进行缩点,把入度为0的点放进队列,再来个很朴实的最长路
#include<bits/stdc++.h>
using namespace std;
const long long inf=0x3f3f3f3f;
const long long maxn=1e6;
int head[maxn],head2[maxn],num,k,k2,dis[maxn],in[maxn],mdis,to[maxn],to2[maxn],next[maxn],next2[maxn],a[maxn],b[maxn],n,m,low[maxn],dfn[maxn],id[maxn],cnt,sum,w[maxn],w2[maxn];
bool vis[maxn];
stack<int>p;
void add(int a,int b){
to[++k]=b;
next[k]=head[a];
head[a]=k;
}
void add2(int a,int b){
to2[++k2]=b;
next2[k2]=head2[a];
head2[a]=k2;
}
void tarjan(int x){ //有向边
low[x]=dfn[x]=++num;
p.push(x);
vis[x]=1;
for(int i=head[x];i;i=next[i]){
int y=to[i];
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
cnt++;//重新编号
int now;
do{
now=p.top();
p.pop();
vis[now]=0;
id[now]=cnt;//记录每个点编号
w2[cnt]+=w[now];
}while(now!=x);
}
}
void bfs(){
stack<int>df;
for(int i=1;i<=cnt;i++){//把入度为0点加进去
if(in[i]==0){
df.push(i);
dis[i]=w2[i];
}
}
while(!df.empty()){
int now=df.top();
df.pop();
for(int i=head2[now];i;i=next2[i]){
int y=to2[i];
if(dis[y]<dis[now]+w2[y]){
dis[y]=dis[now]+w2[y];
df.push(y);
}
}
}
for(int i=1;i<=n;i++)//找最长的路径距离
mdis=max(mdis,dis[i]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=m;i++){
scanf("%d%d",&a[i],&b[i]);
add(a[i],b[i]);
}
for(int i=1;i<=n;i++) //tarjan
if(!dfn[i])
tarjan(i);
for(int i=1;i<=m;i++){//缩点,重新构图
int da=id[a[i]],db=id[b[i]];
if(da!=db){
add2(da,db);
in[db]++;
}
}
bfs();
printf("%d\n",mdis);
return 0;
}
就这么简单啊