题解:P3627 [APIO2009] 抢掠计划

第一道没有看题解 A 掉的蓝题,发篇题解纪念一下。

题目链接#

https://www.luogu.com.cn/problem/P3627

分析#

n,m 都很大,直接跑 SPFA 容易 T。

考虑 Tarjan。由于一个强联通分量之中的路口一定相互可达,那么就可以抢劫该强连通分量中的所有路口。

用 Tarjan 处理强联通分量,同时记录每个强联通分量中的点的权值之和。然后缩点,并跑最长路。最后输出以任一含酒吧的强联通分量为终点的路径中的最大值即可。

Code#

#include<bits/stdc++.h>
#define i64 long long
using namespace std;

const int N=5e5,M=5e5;
int n,m,w[N+5],s,p,bar[N+5];

int tot_edge,hd[N+5];
struct edge{int to,lst;}g[M+5];
void add(int u,int v){
	g[++tot_edge]=edge{v,hd[u]};
	hd[u]=tot_edge;
}

char ch;
void read(int &x){
	x=0,ch=getchar();
	while(ch<48||ch>57)ch=getchar();
	while(ch>=48&&ch<=57)
		x=x*10+ch-48,
		ch=getchar();
}

int tot_pnt,dfn[N+5],low[N+5];
int cnt_scc,scc[N+5],w_scc[N+5];
stack<int>stk;bool instk[N+5];
void tarjan(int x){
	dfn[x]=low[x]=++tot_pnt;
	stk.push(x);instk[x]=true;
	
	int v;
	for(int i=hd[x];i;i=g[i].lst){
		v=g[i].to;
		if(dfn[v]==0){
			tarjan(v);
			low[x]=min(low[x],low[v]);
		}
		else if(instk[v])
			low[x]=min(low[x],dfn[v]);
	}
	
	if(dfn[x]==low[x]){
		++cnt_scc;
		do{
			v=stk.top();stk.pop();
			instk[v]=false;
			scc[v]=cnt_scc,w_scc[cnt_scc]+=w[v];
		}while(x^v);
	}
	return;
}

vector<int>G[N+5];
void solve(){
	int v;
	for(int i=1;i<=n;++i)
		for(int j=hd[i];j;j=g[j].lst){
			v=g[j].to;
			if(scc[i]^scc[v])G[scc[i]].push_back(scc[v]);
		}
	return;
}

queue<int>q;
int dist[N+5];
bool in_q[N+5];
void spfa(){
	for(int i=1;i<=cnt_scc;++i)
		dist[i]=-0x3f3f3f3f;
	
	dist[scc[s]]=w_scc[scc[s]],in_q[scc[s]]=true;
	q.push(scc[s]);
	
	int fr;
	while(!q.empty()){
		fr=q.front();
		for(int v:G[fr]){
			if(dist[v]<dist[fr]+w_scc[v]){
				dist[v]=dist[fr]+w_scc[v];
				if(in_q[v]==false){
					in_q[v]=true;
					q.push(v);
				}
			}
		}
		q.pop();in_q[fr]=false;
	}
	return;
}

int main(){
	cin>>n>>m;
	int x1,x2;
	for(int i=1;i<=m;++i){
		read(x1),read(x2);
		add(x1,x2);
	}
	for(int i=1;i<=n;++i)read(w[i]);
	cin>>s>>p;
	for(int i=1;i<=p;++i)read(bar[i]);
	
	for(int i=1;i<=n;++i)
		if(dfn[i]==0)tarjan(i);
	solve();
	spfa();
	
	int ans=-0x3f3f3f3f;
	for(int i=1;i<=p;++i)
		ans=max(ans,dist[scc[bar[i]]]);
	
	cout<<ans<<endl;
	return 0;
}
posted @   e_zhe  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩