P3627 [APIO2009]抢掠计划

Description:

Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个路口,道路的连接情况如下图所示:

市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。

Analysis:

tarjan缩点建新图,在新图上SPFA跑最长点权路。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define M 500001
#define N 500001
using namespace std;
struct edge{
	int u,v,next;
}e[M],rE[M];
int head[N],st[N],scc[N],dfn[N],low[N],top,num_dfs,num_scc,num_edge1,num_edge2,n,m,S,P;
int vis[N],w[N],W[N],pub[N],dp[N],x[N],y[N];
inline void add(int u,int v,edge E[],int & num){
	E[++num].next = head[u];
	E[num].u = u;
	E[num].v = v;
	head[u] = num;
}
bool cmp(edge & a,edge &b){
	if(a.u == b.u) return a.v < b.v;
	return a.u < b.u;
}
void SPFA(){
	queue<int> Q;
	Q.push(S);
	dp[S] = W[S];
	vis[S] = 1;
	while(!Q.empty()){
		int u = Q.front();Q.pop();
		vis[u] = 0;
		for(int i = head[u];i;i = rE[i].next){
			int v = rE[i].v;
			if(dp[v] < dp[u] + W[v]){
				dp[v] = dp[u] + W[v];
				if(!vis[v]){
					Q.push(v);
					vis[v] = 1;
				}
			}
		}
	}
}
void tarjan(int u){
	dfn[u] = low[u] = ++num_dfs;
	st[++top] = u;
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].v;
		if(!dfn[v]){
			tarjan(v);
			low[u] = min(low[u],low[v]);
		}else{
			if(!scc[v])
				low[u] = min(low[u],dfn[v]);
		}
	}
	if(low[u] == dfn[u]){
		++num_scc;
		scc[u] = num_scc;
		W[num_scc] += w[u];
		while(st[top] != u){
			scc[st[top]] = num_scc;
			W[num_scc] += w[st[top]];
			--top;
		}
		--top;
	}
}
void solve(){
	for(int i = 1;i <= n;++i){
		if(!dfn[i])
			tarjan(i);
	}
	memset(head,0,sizeof(head));
	//newGraph
	for(int i = 1;i <= m;++i){
		if(scc[x[i]] != scc[y[i]]){
			add(scc[x[i]],scc[y[i]],rE,num_edge2);
		}
	}
	//sort(rE+1,rE+1+num_edge2,cmp);
	S = scc[S];
	SPFA();
	int ans = 0;
	for(int i = 1;i <= P;++i){
		ans = max(ans,dp[scc[pub[i]]]);
	}
	printf("%d\n",ans);
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i = 1;i <= m;++i){
		scanf("%d %d",&x[i],&y[i]);
		add(x[i],y[i],e,num_edge1);
	}
	for(int i = 1;i <= n;++i){
		scanf("%d",&w[i]);
	}
	scanf("%d%d",&S,&P);
	for(int i = 1;i <= P;++i){
		scanf("%d",&pub[i]);
	}
	solve();
	return 0;
}
posted @ 2019-03-27 21:36  Zforw  阅读(10)  评论(0编辑  收藏  举报