【图论杂题】:I.atm [Tarjan缩点+拓扑序DP]

题目:

团队链接:atm

题面:

给定 n n n个点 m m m条边的带点权有向图

从1号点出发走一条长度不限的路径

同一条边可多次经过

求经过点的最大点权和,点权不可重复累加
范围: n , m &lt; = 5 e 5 n,m&lt;=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; 
}

Continue……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值