P3469 [POI2008]BLO-Blockade tarjan割點

題意:有n個點m條無向邊,每個點要拜訪其他所有點,總共有n*(n-1)次拜訪次數。保證圖聯通,問禁止通行某個點後一共會少多少次拜訪次數。輸出n行,每行代表 i點禁止通行會減少的拜訪次數。

解:如果這個點不影響圖的聯通性,則答案爲2*(n-1),也即他不能到所有的n-1個點,n-1個點也不能到達他。

如果影響圖的聯通性,也就是割點,則答案再加上各個分量累乘之和,採用tarjan求割點時,由於是像樹一樣遍歷,考慮子樹之間對答案的貢獻和所有子樹之和對除子樹外的點的貢獻。求出的是單向的輸出*2

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100005;
int n,m,x,y,tot,tim;
int dfn[N],low[N],size[N],head[N],cut_point[N];
ll ans[N];
struct Edge{
	int to,nxt;
}edge[1000005];
void add(int x,int y){
	tot++;
	edge[tot].to = y;
	edge[tot].nxt = head[x];
	head[x] = tot;
}
int tarjan(int now){
	int z = 0;size[now] = 1;
	dfn[now] = low[now] = ++tim;
	for(int i=head[now];i;i=edge[i].nxt){
		int t = edge[i].to;
		if(!dfn[t]){
			tarjan(t);
			size[now]+=size[t];
			low[now] = min(low[now],low[t]);
			if(dfn[now]<=low[t]){
				ans[now]+=(ll)z*size[t];
				z+=size[t];
			}
		}else low[now] = min(low[now],dfn[t]);
	}
	ans[now]+=(ll)z*(n-z-1);
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d %d",&x,&y);
		add(x,y);
		add(y,x);
	}
	tarjan(1);
	for(int i=1;i<=n;i++){
		printf("%lld\n",(ans[i]+n-1)<<1);
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章