BLO BZOJ1123无向图连通 割点判断

Description
Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。

Input
输入n<=100000 m<=500000及m条边

Output
输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。

Sample Input
5 5
1 2
2 3
1 3
3 4
4 5
Sample Output
8
8
16
14
8

如果x不是割点,去掉它,就少了它与剩下(n-1)个点的连通,求少去多少有序对,(x,y)(y,x)算2对,所以有2*(n-1)对
如果x是割点,如图橙色的点是割点,它的根是绿色的点,有红色和黄色两个子树,去掉x,则会分成4中颜色,四个连通块。每个连通块去其他的点成有序对,所以在求割点时,求出每个连通块大小,size[s1](n-size[s1])+size[s2](n-size[s2])+……+(n-1)+(n-1-sum)*(1+sum)

在这里插入图片描述

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<queue>
#include<map>
#include<set>
#include<math.h>
#include<vector>
#include<set>
#define INF 0x3f3f3f3f
#define LL long long
#define mem(a, b) memset(a, b, sizeof(a))
#define N 100001
using namespace std;
int n, m, dfn[N], low[N], num, Size[N];
LL ans[N];
bool cut[N];
int ver[N*10], head[N], Next[N*10], tot;  

void add(int x, int y) {
	ver[++tot]=y, Next[tot]=head[x], head[x]=tot;
}

void tarjan(int x) {
	dfn[x]=low[x]=++num, Size[x]=1;
	int flag=0, sum=0;
	for(int i=head[x]; i; i=Next[i]) {
		int y=ver[i];
		if(!dfn[y]) {
			tarjan(y);
			Size[x]+=Size[y];
			low[x]=min(low[x], low[y]);
			if(low[y]>=dfn[x]) { 
				flag++;
				ans[x]+=(LL)(n-Size[y])*Size[y]; 
				sum+=Size[y];//x的子节点个数 
				if(x!=1||flag>1) cut[x]=1;// 如果x不是根节点或者两个以上子节点满足条件,x的割点 
			}
		}
		else low[x]=min(low[x], dfn[y]); 
	}
	if(cut[x])//如果x是割点 
		ans[x]+=(LL)(n-sum-1)*(sum+1)+n-1;
	else
		ans[x]=2*(n-1); 
}

int main() {
	scanf("%d%d",&n, &m);
	for(int i=1; i<=m; i++) {
		int x, y;
		scanf("%d%d",&x, &y);
		add(x, y), add(y, x);
	}
	tarjan(1);//因为所有的towns都连通 
	for(int i=1; i<=n; i++) 
		printf("%lld\n",ans[i]); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值