[POI2008]BLO

[POI2008]BLO-Blockade

题意翻译

在Byteotia有n个城镇。 一些城镇之间由无向边连接。 在城镇外没有十字路口,尽管可能有桥,隧道或者高架公路(反正不考虑这些)。每两个城镇之间至多只有一条直接连接的道路。人们可以从任意一个城镇直接或间接到达另一个城镇。 每个城镇都有一个公民,他们被孤独所困扰。事实证明,每个公民都想拜访其他所有公民一次(在主人所在的城镇)。所以,一共会有n*(n-1)次拜访。

不幸的是,一个程序员总罢工正在进行中,那些程序员迫切要求购买某个软件。

作为抗议行动,程序员们计划封锁一些城镇,阻止人们进入,离开或者路过那里。

正如我们所说,他们正在讨论选择哪些城镇会导致最严重的后果。

编写一个程序:

读入Byteotia的道路系统,对于每个被决定的城镇,如果它被封锁,有多少访问不会发生,输出结果。

输入输出格式

第一行读入n,m,分别是城镇数目和道路数目

城镇编号1~n

接下来m行每行两个数字a,b,表示a和b之间有有一条无向边

输出n行,每行一个数字,为第i个城镇被锁时不能发生的访问的数量。

翻译提供者:Park

给定一张无向图,求每个点被封锁之后有多少个有序点对(x,y)(x!=y,1<=x,y<=n)满足x无法到达y

输入样例#1: 复制
5 5
1 2
2 3
1 3
3 4
4 5
输出样例#1: 复制
8
8
16
14
8

cy41的题解

还有人把书拍了照发到网上的,佩服。

考虑删除的点为割点和非割点:设总共有n个点,第i个点断开;

  1. 非割点,不会改变其余n-1个点的连通性,那么剩下的n-1个点都是连通的,故只有i点与别的点都不连通,那么此时的有序点对为:2*(n-1);
  2. 割点,那么去掉这些与i点相连的边后,会划分成若干个连通块,若我们已知每个连通块内的点数,那么将他们两两相乘再相加即为有序点对;

好的,这时问题转化为了如何快速的求出去掉i点后,各个连通块内的点个数。

我们其实可以将连通块的种类分为3种,其一是i点自身,二是除了i点的与之有直连边的割点构成的连通块,三是除去i,与之有直连边的割点以外,剩下的所有点构成的块。

其中SIZE[S1]*(n-SIZE[S1])表示该连通块到其他别的点都是不连通的,1*(n-1)为那个去掉的第i个点到其他点不连通,

最后那个()*()就是除了割点,除了被去掉的这个点构成的点的集合,到割点及i点的不连通。

时间复杂度\(O(n)\)

co int N=1e5+1,M=5e5+1;
int head[N],ver[M*2],next[M*2];
int dfn[N],low[N],siz[N];
ll ans[N];
bool cut[N];
int n,m,tot,num;

il 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,siz[x]=1;
	int flag=0,sum=0;
	for(int i=head[x],y;i;i=next[i]){
		if(!dfn[y=ver[i]]){
			tarjan(y);
			low[x]=std::min(low[x],low[y]),siz[x]+=siz[y];
			if(low[y]>=dfn[x]){
				++flag;
				ans[x]+=(ll)siz[y]*(n-siz[y]);
				sum+=siz[y];
				if(x!=1||flag>1) cut[x]=1;
			}
		}
		else low[x]=std::min(low[x],dfn[y]);
	}
	if(cut[x]) ans[x]+=(ll)(n-sum-1)*(sum+1)+(n-1);
	else ans[x]=2*(n-1);
}
int main(){
	read(n),read(m);
	for(int i=1,x,y;i<=m;++i){
		read(x),read(y);
		if(x==y) continue;
		add(x,y),add(y,x);
	}
	tarjan(1);
	for(int i=1;i<=n;++i) printf("%lld\n",ans[i]);
	return 0;
}

posted on 2019-05-29 17:22  autoint  阅读(155)  评论(0)    收藏  举报

导航