BZOJ_1179_[Apio2009]Atm_tarjan+spfa
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1179
分析:
显然有环没法直接最长路,那就缩个点再跑。
酒吧连汇点。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 #define N 500050 6 int head[N],to[N<<1],nxt[N<<1],val[N],can[N],cancan[N]; 7 int n,m,bel[N],dfn[N],low[N],st[N],top,scc,tot,cnt,S,T; 8 int ins[N],sum[N],X[N],Y[N],Q[N],l,r,dis[N],inq[N]; 9 inline void add(int u,int v){ 10 to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt; 11 } 12 void tarjan(int x){ 13 st[top++]=x;ins[x]=1;dfn[x]=low[x]=++tot; 14 for(int i=head[x];i;i=nxt[i]){ 15 if(!dfn[to[i]]){ 16 tarjan(to[i]); 17 low[x]=min(low[x],low[to[i]]); 18 }else if(ins[to[i]])low[x]=min(low[x],dfn[to[i]]); 19 } 20 if(dfn[x]==low[x]){ 21 int t=st[--top];ins[t]=0; 22 bel[t]=++scc; 23 sum[scc]+=val[t]; 24 cancan[scc]|=can[t]; 25 while(t!=x){ 26 t=st[--top];ins[t]=0; 27 bel[t]=scc; 28 sum[scc]+=val[t]; 29 cancan[scc]|=can[t]; 30 } 31 } 32 } 33 int main(){ 34 scanf("%d%d",&n,&m); 35 int x,y; 36 for(int i=1;i<=m;i++){ 37 scanf("%d%d",&x,&y); 38 add(x,y); 39 X[i]=x,Y[i]=y; 40 } 41 for(int i=1;i<=n;i++){ 42 scanf("%d",&val[i]); 43 } 44 scanf("%d%d",&S,&x); 45 T=n+1; 46 for(int i=1;i<=x;i++){ 47 scanf("%d",&y); 48 can[y]=1; 49 } 50 for(int i=1;i<=n;i++){ 51 if(!dfn[i])tarjan(i); 52 } 53 memset(head,0,sizeof(head));cnt=0; 54 for(int i=1;i<=m;i++){ 55 if(bel[X[i]]!=bel[Y[i]])add(bel[X[i]],bel[Y[i]]); 56 } 57 for(int i=1;i<=scc;i++)if(cancan[i])add(i,T); 58 S=bel[S]; 59 Q[r++]=S;inq[S]=1;dis[S]=sum[S]; 60 while(l^r){ 61 int x=Q[l++];inq[x]=0;if(l==n+10)l=0; 62 for(int i=head[x];i;i=nxt[i]){ 63 if(dis[to[i]]<dis[x]+sum[to[i]]){ 64 dis[to[i]]=dis[x]+sum[to[i]]; 65 if(!inq[to[i]]){ 66 inq[to[i]]=1;Q[r++]=to[i];if(r==n+10)r=0; 67 } 68 } 69 } 70 } 71 printf("%d",dis[T]); 72 }