3896. 【NOIP2014模拟10.26】战争游戏

在这里插入图片描述
鉴于如此一道恶心的题,作者还花了一个晚上草草学了tarjan。
在这里插入图片描述
在这里插入图片描述
于是乎,这道题就是道tarjan
具体怎么实现呢?正解上有个什么树形DP,看的我一脸懵逼。
这道题可以运用到tarjan一个高科技的算法叫——割点。
这里就不再介绍怎么打tarjan了,切入正题。
我们先回忆下割点。
也就是在一个无向图中,将一个点G及其相关的边全部扔掉,会使这个图不在联通,便称点G为割点(作者个人理解)
看完上面的,是不是感觉和题目大意有点相像?
在这里插入图片描述
我先在做tarjan的同时可以很轻松的求得其子节点的数量,从而得知联通块的大小(如蓝色圆圈{\color{Blue} 蓝色圆圈}紫色圆圈{\color{purple} 紫色圆圈}橙色圆圈{\color{orange} 橙色圆圈})然后很自然的就能求出子节点的方案数
由上面,也很容易推出绿色圆圈{\color{green} 绿色圆圈}绿的方案数

#include<cstdio>
#include<algorithm>
#define N 50001
using namespace std;
int n,m,i,x,y,to,t,low[N],ans[N],dfn[N],last[200001],num[N];
struct node
{
	int go,last;
}p[200001];
void make(int x,int y){p[++t].go=y;p[t].last=last[x];last[x]=t;}
void tarjan(int x)
{
	num[x]=1; dfn[x]=low[x]=++to;
	int tot=0;
	for (int i=last[x];i;i=p[i].last)
	{
		int y=p[i].go;
		if (!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if (dfn[x]<=low[y])
			{
				ans[x]+=num[y]*(n-1-num[y]);
				tot+=num[y];
			}
			num[x]+=num[y];
		}else low[x]=min(low[x],dfn[y]);
	}
	ans[x]+=tot*(n-1-tot);
}
int main()
{
	freopen("a.in","r",stdin);
	scanf("%d%d",&n,&m);
	for (i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		make(x,y); make(y,x);
	}
	to=0;
	tarjan(1);
	for (i=1;i<=n;i++) printf("%d\n",ans[i]/2+n-1);
}

转载于:https://www.cnblogs.com/Sport-river/p/10390125.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值