[题目链接](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;
}