BZOJ_1179_[Apio2009]Atm_tarjan+spfa

BZOJ_1179_[Apio2009]Atm_tarjan+spfa

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1179

分析:

显然有环没法直接最长路,那就缩个点再跑。

酒吧连汇点。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 500050
int head[N],to[N<<1],nxt[N<<1],val[N],can[N],cancan[N];
int n,m,bel[N],dfn[N],low[N],st[N],top,scc,tot,cnt,S,T;
int ins[N],sum[N],X[N],Y[N],Q[N],l,r,dis[N],inq[N];
inline void add(int u,int v){
	to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;	
}
void tarjan(int x){
	st[top++]=x;ins[x]=1;dfn[x]=low[x]=++tot;
	for(int i=head[x];i;i=nxt[i]){
		if(!dfn[to[i]]){
			tarjan(to[i]);
			low[x]=min(low[x],low[to[i]]);
		}else if(ins[to[i]])low[x]=min(low[x],dfn[to[i]]);
	}
	if(dfn[x]==low[x]){
		int t=st[--top];ins[t]=0;
		bel[t]=++scc;
		sum[scc]+=val[t];
		cancan[scc]|=can[t];
		while(t!=x){
			t=st[--top];ins[t]=0;
			bel[t]=scc;
			sum[scc]+=val[t];
			cancan[scc]|=can[t];
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	int x,y;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		add(x,y);
		X[i]=x,Y[i]=y;
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&val[i]);	
	}
	scanf("%d%d",&S,&x);
	T=n+1;
	for(int i=1;i<=x;i++){
		scanf("%d",&y);
		can[y]=1;	
	}
	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(bel[X[i]]!=bel[Y[i]])add(bel[X[i]],bel[Y[i]]);	
	}
	for(int i=1;i<=scc;i++)if(cancan[i])add(i,T);
	S=bel[S];
	Q[r++]=S;inq[S]=1;dis[S]=sum[S];
	while(l^r){
		int x=Q[l++];inq[x]=0;if(l==n+10)l=0;
		for(int i=head[x];i;i=nxt[i]){
			if(dis[to[i]]<dis[x]+sum[to[i]]){
				dis[to[i]]=dis[x]+sum[to[i]];
				if(!inq[to[i]]){
					inq[to[i]]=1;Q[r++]=to[i];if(r==n+10)r=0;
				}
			}
		}
	}
	printf("%d",dis[T]);
}

 

posted @ 2018-02-21 19:30  fcwww  阅读(184)  评论(0编辑  收藏  举报