【BZOJ】【APIO2009】【ATM】【强连通分量+DP】

传送门:

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

Tarjan缩点+DAG上DP,水……

学习了dr神犇的代码风格,虽然一直不知道TOPL是神马意思……

Code:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
const int maxn=500010;
int Scc_num,Blg[maxn],s;
int sor[maxn],sor_2[maxn];
int cub[maxn],cub_2[maxn];
int n,m;
namespace Scc{
	stack<int>S;
	vector<int>G[maxn];
	int dfn[maxn],tot,low[maxn];
	void add(int u,int v){
		G[u].push_back(v);
	}
	bool ins[maxn];
	void Tarjan(int u){
		dfn[u]=low[u]=++tot;
		ins[u]=1;S.push(u);
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i];
			if(!dfn[v]){
				Tarjan(v);
				low[u]=min(low[u],low[v]);
			}else
				if(ins[v])
					low[u]=min(low[u],dfn[v]);
		}
		if(dfn[u]==low[u]){
			Scc_num++;
			int v;
			do{
				v=S.top();S.pop();
				ins[v]=0;
				Blg[v]=Scc_num;
			}while(u!=v);
		}
	}
};
namespace TOPL{
	int f[maxn];
	vector<int>G[maxn];
	void add(int u,int v){
		G[u].push_back(v);
	}
	int bfs(){
		f[Blg[s]]=sor_2[Blg[s]];
		queue<int>q;
		q.push(Blg[s]);
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int i=0;i<G[u].size();i++){
				int v=G[u][i];
				if(f[v]<f[u]+sor_2[v]){
					f[v]=f[u]+sor_2[v];
					q.push(v);
				}
			}
		}
		int maxx=0;
		for(int i=1;i<=Scc_num;i++)
			if(cub_2[i])
				maxx=max(maxx,f[i]);
		return maxx;
	}
	void solve(){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			Scc::add(u,v);
		}
		for(int i=1;i<=n;i++)
		scanf("%d",&sor[i]);
		int p;
		scanf("%d%d",&s,&p);
		for(int i=1;i<=p;i++)
			scanf("%d",&cub[i]);
		for(int i=1;i<=n;i++)
			if(!Scc::dfn[i])
				Scc::Tarjan(i);
		
		for(int i=1;i<=n;i++)
			sor_2[Blg[i]]+=sor[i];
		for(int i=1;i<=p;i++)
			cub_2[Blg[cub[i]]]=1;
			
		for(int i=1;i<=n;i++)
		for(int j=0;j<Scc::G[i].size();j++){
			int v=Scc::G[i][j];
			if(Blg[i]!=Blg[v])
				add(Blg[i],Blg[v]);
		}
		
		printf("%d\n",bfs());
	}
};
int main(){
	TOPL::solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值