P3469 [POI2008]BLO-Blockade

好神的一道题

减去非割点,因为是有序点对,答案贡献为\(2*(n-1)\)

减去割点\(i\),分成了若干连通块,设搜索树上,有\(t\)个点满足割点判定法则,每个联通块节点构成情况:

1.被割的 割点\(i\) 2.\(t\)个连通块,由以\(s_k(1\le k\le t)\)为根子树中节点构成 3.除上述节点以外节点

\(siz[x]\)\(x\)为根子树大小,删掉\(i\),不连通有序对个数

\[\sum_{i=1}^tsiz[s_i]*(n-siz[s_i])+1*(n-1)+(n-1-\sum_{k=1}^tsiz[s_k])*(1+\sum_{k=1}^tsiz[s_k]) \]

#include<cstdio>
const int N = 100010,M = 500010;
using namespace std;
struct edge{int to,next;}e[M<<1]; int head[N],tot;
int dfn[N],low[N],siz[N],cut[N]; int n,m,num; long long ans[N];
inline void add(int u,int v){e[++tot] = (edge){v,head[u]}; head[u] = tot;}
inline int min(int a,int b){return a < b ? a : b;}
void tarjan(int x){
	dfn[x] = low[x] = ++num; siz[x] = 1;
	int flag = 0,sum = 0;
	for(int i = head[x];i;i = e[i].next){
		int v = e[i].to;
		if(!dfn[v]){
			tarjan(v); siz[x] += siz[v];
			low[x] = min(low[x],low[v]);
			if(low[v] >= dfn[x]){
				++flag;
				ans[x] += (long long)siz[v] * (n - siz[v]);
				sum += siz[v];
				if(x != 1 || flag > 1) cut[x] = 1;
			}
		}
		else low[x] = min(low[x],dfn[v]);
	}
	if(cut[x]) ans[x] += (long long)(n - sum -1) * (sum+1) + (n - 1);
	else ans[x] = 2 * (n - 1);
}
int main(){
	scanf("%d%d",&n,&m); tot = 1; int x,y;
	for(int i = 1;i <= m;++i){
		scanf("%d%d",&x,&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]);
} 
posted @ 2020-08-24 15:37  INFP  阅读(83)  评论(0编辑  收藏  举报