抢掠计划

[题目链接](https://www.luogu.com.cn/problem/P3627)

思路

路可以重复走但是钱不能重复拿,对于一个强连通分量里的点我们肯定把钱都拿光,tarjan缩点

ans维护从s点出发到每个点最多能拿到多少钱,vis维护每个点能否访问到

然而直接dfs会t,考虑到每次判断从当前点到儿子ans[u]+ww[v]>ans[v]?访问儿子:不访问

不妨所有儿子中先更新较大的儿子

玄学堆优化+bfs

代码

dfs:

#include<bits/stdc++.h>
using namespace std;
int uu[600100],vv[600000],cnt=0,head[600000],dfn[600000],low[600000],t=0,in[600000],sta[600000],stac=0,
color[600000],colornum=0,ww[600000],w[600000],ans[600000],vis[600000];
struct node{
	int to,nxt;
}road[600000];
void build(int u,int v)
{
	road[++cnt].to=v;
	road[cnt].nxt=head[u];
	head[u]=cnt;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++t;
	in[u]=1;sta[++stac]=u;
	for(int i=head[u];i;i=road[i].nxt)
	{
		int v=road[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(in[v]) low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		color[u]=++colornum;
		in[u]=0;
		ww[colornum]+=w[u];
		while(sta[stac]!=u)
		{
			color[sta[stac]]=colornum;
			in[sta[stac]]=0;
			ww[colornum]+=w[sta[stac]];
			stac--;
		}
		stac--;
	}
}
void dfs(int u)
{
	vis[u]=1;
	for(int i=head[u];i;i=road[i].nxt)
	{
		int v=road[i].to;
		if(ans[u]+ww[v]>ans[v]) 
		{
			ans[v]=ans[u]+ww[v];
			dfs(v);
		}
	}
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>uu[i]>>vv[i];
		build(uu[i],vv[i]);
	}
	for(int i=1;i<=n;i++) cin>>w[i];
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i]) tarjan(i);
	}
	int s,p;
	cin>>s>>p;
	memset(head,0,sizeof(head));
	cnt=0;
	for(int i=1;i<=m;i++)
	{
		if(color[uu[i]]!=color[vv[i]])
		{
			build(color[uu[i]],color[vv[i]]);
		}
	}
	memset(ans,0,sizeof(ans));
	memset(vis,0,sizeof(vis));
	ans[color[s]]=ww[color[s]];//QAQ带上color 
	vis[color[s]]=1;
	for(int i=head[color[s]];i;i=road[i].nxt)
	{
		int v=road[i].to;
		if(ans[color[s]]+ww[v]>ans[v]) 
		{
			ans[v]=ans[color[s]]+ww[v];//是ww不是w呀 
			dfs(v);
		}
	}
	int maxn=-1;
	for(int i=1;i<=p;i++)
	{
		int x;
		cin>>x;
		if(vis[color[x]]) maxn=max(maxn,ans[color[x]]);//QAQ带上color 
	}
	cout<<maxn;
	return 0;
}

bfs

#include<bits/stdc++.h>
using namespace std;
int uu[600100],vv[600000],cnt=0,head[600000],dfn[600000],low[600000],t=0,in[600000],sta[600000],stac=0,
color[600000],colornum=0,ww[600000],w[600000],ans[600000],vis[600000];
priority_queue< pair<int,int> > q1;
priority_queue< pair<int,int> > q2;
struct node{
	int to,nxt;
}road[600000];
void build(int u,int v)
{
	road[++cnt].to=v;
	road[cnt].nxt=head[u];
	head[u]=cnt;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++t;
	in[u]=1;sta[++stac]=u;
	for(int i=head[u];i;i=road[i].nxt)
	{
		int v=road[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(in[v]) low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		color[u]=++colornum;
		in[u]=0;
		ww[colornum]+=w[u];
		while(sta[stac]!=u)
		{
			color[sta[stac]]=colornum;
			in[sta[stac]]=0;
			ww[colornum]+=w[sta[stac]];
			stac--;
		}
		stac--;
	}
}
void bfs()
{
	while(!q2.empty())
	{
		int u=q2.top().first;q2.pop();
		for(int i=head[u];i;i=road[i].nxt)
		{
			int v=road[i].to;
			vis[v]=1;
			if(ans[u]+ww[v]>ans[v]) 
			{
				ans[v]=ans[u]+ww[v];
				q2.push(make_pair(v,ans[v]));
			}
		}
	}
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>uu[i]>>vv[i];
		build(uu[i],vv[i]);
	}
	for(int i=1;i<=n;i++) cin>>w[i];
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i]) tarjan(i);
	}
	int s,p;
	cin>>s>>p;
	memset(head,0,sizeof(head));
	cnt=0;
	for(int i=1;i<=m;i++)
	{
		if(color[uu[i]]!=color[vv[i]])
		{
			build(color[uu[i]],color[vv[i]]);
		}
	}
	memset(ans,0,sizeof(ans));
	memset(vis,0,sizeof(vis));
	ans[color[s]]=ww[color[s]];//QAQ带上color 是ww不是w呀
	vis[color[s]]=1;
	for(int i=head[color[s]];i;i=road[i].nxt)
	{
		int v=road[i].to;
		if(ans[color[s]]+ww[v]>ans[v]) 
		{
			ans[v]=ans[color[s]]+ww[v];
			q1.push(make_pair(v,ans[v]));
		}
	}
	while(!q1.empty())
	{
		int u=q1.top().first;
		q1.pop();
		vis[u]=1;
		q2.push(make_pair(u,ans[u]));//QAQ
		bfs();
	}
	int maxn=-1;
	for(int i=1;i<=p;i++)
	{
		int x;
		cin>>x;
		if(vis[color[x]]) maxn=max(maxn,ans[color[x]]);//QAQ带上color 
	}
	cout<<maxn;
	return 0;
}
原文地址:https://www.cnblogs.com/qwq-/p/13637918.html