这道题目还是先用tarjan缩点,然后用拓扑序进行一下计算
和【tarjan+拓扑】P2272 [ZJOI2007]最大半连通子图 一样
代码
#include<bits/stdc++.h>
using namespace std;
const int maxm=5e5+5;
const int maxn=5e5+5;
int n,v,m,f[maxm],tot,flag[maxn],h[maxn],t[maxm],bar[maxn],head[maxn],st,ed;
int dis[maxn],ca[maxn],ans;
struct edge
{
int to,nxt;
}e[maxm],G[maxm];
int cnt,dfn[maxn],vis[maxn],low[maxn],times,s[maxn],top,instack[maxn];
int col_num,belong[maxn],size[maxn];
void add(int a,int b)
{
e[++cnt].to=b;
e[cnt].nxt=head[a];
head[a]=cnt;
}
void addd(int a,int b)
{
G[++tot].to=b;
G[tot].nxt=h[a];
h[a]=tot;
}
void tarjan(int u)
{
dfn[u]=low[u]=++times;
instack[u]=1; s[++top]=u;
for(int i=head[u];i;i=e[i].nxt)
{
int to=e[i].to;
if(!dfn[to])
{
tarjan(to);
low[u]=min(low[u],low[to]);
}
else if(instack[to]) low[u]=min(low[u],dfn[to]);
}
if(low[u]==dfn[u])
{
col_num++;
do
{
v=s[top--];
size[col_num]+=ca[v];
belong[v]=col_num;
instack[v]=0;
flag[col_num]=1;
if(bar[v]) vis[col_num]=1;
}while(u!=v);
}
}
int num[maxm],in[maxn];
void addedge(int x)
{
int u=belong[x];
if(!flag[u]) return;
for(int i=head[x];i;i=e[i].nxt)
{
int to=belong[e[i].to];
if(to!=u && flag[to]) addd(u,to),in[to]++;
}
}
void topo(int x)
{
queue <int> q;
q.push(x);
dis[x]=size[x];
if(vis[x]) ans=max(ans,dis[x]);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=h[u];i;i=G[i].nxt)
{
int to=G[i].to;
--in[to];
if(dis[to]<dis[u]+size[to])
dis[to]=dis[u]+size[to];
if(vis[to]) ans=max(ans,dis[to]);
if(!in[to]) q.push(to);
}
}
}
int main()
{
freopen("P3627_3.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&f[i],&t[i]);
add(f[i],t[i]);
}
for(int i=1;i<=n;i++) scanf("%d",&ca[i]);
scanf("%d%d",&st,&ed);
int x;
for(int i=1;i<=ed;i++)
{
scanf("%d",&x);
bar[x]=1;
}
tarjan(st);
for(int i=1;i<=n;i++)
addedge(i);
topo(belong[st]);
printf("%d",ans);
return 0;
}