题目:
团队链接:atm
题面:
给定 n n n个点 m m m条边的带点权有向图
从1号点出发走一条长度不限的路径
同一条边可多次经过
求经过点的最大点权和,点权不可重复累加
范围:
n
,
m
<
=
5
e
5
n,m<=5e5
n,m<=5e5
样例:
输入:
7 7
1 7
4 1
1 2
2 3
3 4
2 5
5 6
5 3 9 4 10 2 7
1 2
2 6
输出:
33
题解:
tarjan对于每个强连通分量进行缩点,建张新图,然后按照拓扑序DP即可。(真心的图论杂题,,,,)
代码:
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int ocean=1e9+7;
const int sea=5e5+7;
struct see{int ver,edge,next;}e[sea];
struct se{int ver,edge,next;}E[sea];
int n,m,S,T,tot,ans=0,w[sea],last[sea],dfn[sea],low[sea],sta[sea],id[sea],d[sea],res[sea];
int cnt,Tot,st,deep,Last[sea],W[sea];
queue<int>Q;
void add(int x,int y){e[++tot].ver=y;e[tot].next=last[x];last[x]=tot;}
void Add(int x,int y){E[++Tot].ver=y;E[Tot].next=Last[x];Last[x]=Tot;}
void tarjan(int x)
{
dfn[x]=low[x]=++deep;
sta[++st]=x;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].ver;
if(!dfn[y]) tarjan(y),low[x]=min(low[y],low[x]);
else if(!id[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
id[x]=++cnt;
while(sta[st]!=x) id[sta[st--]]=cnt;
--st;
}
}
int main()
{
n=read(); m=read();
for(int i=1;i<=m;i++){int x=read(),y=read();add(x,y);}
for(int i=1;i<=n;i++) w[i]=read();
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int x=1;x<=n;x++)
{
W[id[x]]+=w[x];
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].ver;
if(id[x]!=id[y]) ++d[id[y]],Add(id[x],id[y]);
}
}
for(int i=1;i<=cnt;i++){res[i]=-ocean;if(!d[i]) Q.push(i);}
S=read(); T=read(); res[id[S]]=0;
while(!Q.empty())
{
int x=Q.front();Q.pop(); res[x]+=W[x];
for(int i=Last[x];i;i=E[i].next)
{
int y=E[i].ver;
if(!(--d[y])) Q.push(y);
res[y]=max(res[y],res[x]);
}
}
for(int i=1;i<=T;i++) {int x=read();ans=max(ans,res[id[x]]);}
printf("%d\n",ans);
return 0;
}