好神的一道题
减去非割点,因为是有序点对,答案贡献为(2*(n-1))
减去割点(i),分成了若干连通块,设搜索树上,有(t)个点满足割点判定法则,每个联通块节点构成情况:
1.被割的 割点(i) 2.(t)个连通块,由以(s_k(1le kle 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
",ans[i]);
}