【tarjan+拓扑】P3627 [APIO2009]抢掠计划

17 篇文章 0 订阅

 

这道题目还是先用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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值