P3469 [POI2008]BLO-Blockade

Posted suxxsfe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3469 [POI2008]BLO-Blockade相关的知识,希望对你有一定的参考价值。

tarjan 割点
P3469 [POI2008]BLO-Blockade

问题描述

B 城有 (n) 个城镇,(m) 条双向道路。
每条道路连结两个不同的城镇,没有重复的道路,所有城镇连通。
把城镇看作节点,把道路看作边,容易发现,整个城市构成了一个无向图。

输入格式

第一行包含两个整数 (n)(m)
接下来 (m) 行,每行包含两个整数 (a)(b),表示城镇 (a)(b) 之间存在一条道路。

输出格式

输出共 (n) 行,每行输出一个整数。
(i) 行输出的整数表示把与节点 (i) 关联的所有边去掉以后(不去掉节点 (i) 本身),无向图有多少个有序点 ((x,y)),满足 (x)(y) 不连通。

数据范围

(nle 100000)(mle500000)


先用 tarjan 求出割点,对于非割点,除它以外的点的连通性不受他的影响,所以只有它与其它点会不连通,答案是 (2(n-1))

对于那些是割点的点,它会把整个图分成若干个联通块(假设是 (k) 个),那么不连通的点对数就是

[sum_{i=1}^k a_icdot (n-a_i)+2(n-1) ]

就是说每个联通块的点数((a_i)),都与其它点,除去当前这个割点((n-a_i-1)),不相连通
当然这些联通块都是不包含当前这个割点的

那么如何求这些联通块?
tarjan 的时候,对于有向边 ((u,v))(low_vge dfn_u) 就说明如果不经过 (u)(v) 和它后面的点就不能回到 (u) 之前,那么搜索树中以 (v) 为根的子树,正是一个这样的联通快
假设这个搜索树子树的大小是 (size_v),那么这个 (size_v) 就是 (a_i),直接加到答案里就行了
(sum_{(u,v)}size_v=sum),则还应该有一个大小为 (n-sum-1) 的联通块,就是在搜索树中从 (u)“往上”有一个联通块,那么答案还要再加 ((n-sum-1)cdot (n-(n-sum-1)-1)=sum(n-sum-1))

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<‘0‘||c>‘9‘){if(c==‘-‘) y=0;c=std::getchar();}
	while(c>=‘0‘&&c<=‘9‘){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
//tarjan 割点 
#define N 100006
#define M 1000006
int n,m;
int fir[N],nex[M],to[M],tot;
int cut[N],dfn[N],low[N],dfscnt;
LL ans[N];
inline void add(int x,int y){
	to[++tot]=y;
	nex[tot]=fir[x];fir[x]=tot;
}
int tarjan(int u,int fa){//return size of subtree u
	dfn[u]=low[u]=++dfscnt;
	int children=0,size=1,size_v,sum=0;
	for(reg int v,i=fir[u];i;i=nex[i]){
		v=to[i];
		if(!dfn[v]){
			size_v=tarjan(v,fa);
			size+=size_v;
			low[u]=std::min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				sum+=size_v;ans[u]+=(LL)size_v*(n-size_v-1);
				if(u!=fa) cut[u]=1;
			}
			children++;
		}
		else low[u]=std::min(low[u],dfn[v]);
	}
	ans[u]+=(LL)sum*(n-sum-1);
	if(children>1&&u==fa) cut[u]=1;
//		std::printf("u : %d  size : %d ans : %d
",u,size,ans[u]);
	return size;
}
int main(){
	n=read();m=read();
	for(reg int u,v,i=1;i<=m;i++){
		u=read();v=read();
		add(u,v);add(v,u);
	}
	tarjan(1,1);
	for(reg int i=1;i<=n;i++)
		std::printf("%lld
",(n-1)*2+cut[i]*ans[i]);
//		
//		EN;EN;
//		for(reg int i=1;i<=n;i++) std::printf("dfn : %d  low : %d  size : %d
",dfn[i],low[i],size[i]);
	return 0;
}

以上是关于P3469 [POI2008]BLO-Blockade的主要内容,如果未能解决你的问题,请参考以下文章

P3469 [POI2008]BLO-Blockade

luogu P3469 [POI2008]BLO-Blockade 割点

P3469 [POI2008]BLO-Blockade

P3469 [POI2008]BLO-Blockade 割点 tarjan

P3469 [POI2008]BLO-Blockade tarjan

AC日记——[POI2008]BLO-Blockade 洛谷 [POI2008]BLO-Blockade