Luogu_P3469 [POI2008]BLO-Blockade

### tarjan割点

题目链接
假如\(i\)不是割点
那么只会\(i\)分离出去,因为是有顺序的
所以答案是\(2*(n-1)\)
假如\(i\)是割点
那么设\(s\)\(i\)的儿子,且\(s\)\(low\)值>=\(dfn[i]\)
除去\(s\)还有一些是到\(root\)
或是\(low\)值小于\(dfn[i]\)的点,也就是可以和\(root\)构成连通块的点
那么答案明显就是
\(size[s1]*(n-size[s1])+size[s2]*(n-size[s2])+……+size[st]*(n-size[st])+1*(n-1)+(n-1-sum)*(1+sum)\)
\(sum\)\(size\)的和
所以在求割点的时候就可以求出\(ans\)


代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxm=500010;
int rt,n,m,head[maxm],tot,dfn[maxm],low[maxm],siz[maxm],num;
bool cut[maxm];
ll ans[maxm];
struct node{
    int nxt,to;
    #define nxt(x) e[x].nxt
    #define to(x) e[x].to
}e[maxm<<1];
inline void add(int from,int to){
    to(++tot)=to;nxt(tot)=head[from];head[from]=tot;
}
void tarjan(int x){
    low[x]=dfn[x]=++num;siz[x]=1;
    int fl=0,sum=0;
    for(int i=head[x];i;i=nxt(i)){
        int y=to(i);
        if(!dfn[y]){
            tarjan(y);
            siz[x]+=siz[y];
            low[x]=min(low[x],low[y]);
            if(low[y]>=dfn[x]){
                ans[x]+=(ll)siz[y]*(n-siz[y]);
                sum+=siz[y];fl++;
                if(x!=1 || fl>1) cut[x]=1;
            }
        }else low[x]=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()
{
    scanf("%d%d",&n,&m);
    for(int x,y,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]);
    return 0;
}
01-26 11:52