给定一个有向图,从指定起点出发,到任意一个指定终点停止,求经过的所有结点的最大点权和。点数、边数<=500000
先对所有起点可达的点做一遍拓扑排序,然后用队列维护入度为0的点,每次取出队首元素,用它的答案更新其他点即可
好像有一个点会RE?
#include<stdio.h> #include<stdlib.h> #include<string.h> int u[500005],v[500005],w[500005],first[500005],next[500005],bar[500005],f[500005],d[500005],vis[500005]; int pre[500005],link[500005],sta[500005],sccno[500005],q[500005]; int clo=0,top=0; void find(int x) { int i,y; pre[x]=link[x]=++clo; sta[++top]=x; for(i=first[x];i!=0;i=next[i]) if(sccno[v[i]]==0) { if(pre[v[i]]==0) find(v[i]); if(link[x]>link[v[i]]) link[x]=link[v[i]]; } if(pre[x]==link[x]) { while(sta[top]!=x) sccno[sta[top--]]=x; sccno[sta[top--]]=x; } } void dfs(int x) { int i; vis[x]=1; for(i=first[x];i!=0;i=next[i]) if(vis[v[i]]==0) dfs(v[i]); } int main() { int n,m,s,p,i,head=0,tail=0,max=0; scanf("%d%d",&n,&m); for(i=1;i<=m;i++) { scanf("%d%d",&u[i],&v[i]); next[i]=first[u[i]]; first[u[i]]=i; } for(i=1;i<=n;i++) scanf("%d",&w[i]); scanf("%d%d",&s,&p); for(i=1;i<=p;i++) scanf("%d",&bar[i]); for(i=1;i<=n;i++) if(sccno[i]==0) find(i);//计算强连通分量 memset(first,0,sizeof(first)); memset(next,0,sizeof(next)); for(i=1;i<=m;i++)//缩点 { u[i]=sccno[u[i]]; v[i]=sccno[v[i]]; if(u[i]!=v[i]) { next[i]=first[u[i]]; first[u[i]]=i; } } for(i=1;i<=n;i++) if(sccno[i]!=i) w[sccno[i]]+=w[i]; dfs(sccno[s]); for(i=1;i<=m;i++) if(u[i]!=v[i]&&vis[u[i]]==1) f[v[i]]++; q[tail++]=sccno[s]; while(head<tail) { d[q[head]]+=w[q[head]]; for(i=first[q[head]];i!=0;i=next[i]) { if(d[v[i]]<d[u[i]]) d[v[i]]=d[u[i]]; f[v[i]]--; if(f[v[i]]==0) q[tail++]=v[i]; } head++; } for(i=1;i<=p;i++) if(max<d[sccno[bar[i]]]) max=d[sccno[bar[i]]]; printf("%d",max); return 0; }