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]);
}