bzoj1123 割点性质应用

 删掉无向图上任意一点,请求出将会增加的不连通的点对数

将无向图联通性的问题转化到搜索树方向上考虑

如果一个点不是割点,那么删掉该点的答案很简单,就是2*(n-1)

如果点u是割点,同时u在搜索树上有t个子节点,那么删掉u点后就会出现t+2个联通分量

  1.t个包含不同子节点的联通分量:每个子节点联通分量的贡献是size[son]*(n-size[son])

  2.结点u:u的贡献是(n-1)

  3.剩下部分,即u子树除外其他的点形成的联通分量:这部分的贡献是n-1-sum{size[son]}

在tarjan时同时求出size数组即可

#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
struct Edge{int to,nxt;}edge[maxn<<1];
int head[maxn],tot,n,m;
long long ans[maxn];

void init(){
    tot=0;
    memset(head,-1,sizeof head);
}
void addedge(int u,int v){
    edge[tot].to=v;
    edge[tot].nxt=head[u];
    head[u]=tot++;
}

int cut[maxn],low[maxn],dfn[maxn],size[maxn],ind;
void tarjan(int u){
    dfn[u]=low[u]=++ind;
    size[u]=1;
    int flag=0,sum=0;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
            size[u]+=size[v];
            if(low[v]>=dfn[u]){
                flag++;
                ans[u]+=(long long)size[v]*(n-size[v]);
                sum+=size[v];
                if(u!=1 || flag>1)
                    cut[u]=true;//u是割点 
            } 
        }
        else low[u]=min(low[u],dfn[v]);//回边 
    }
    if(cut[u])
        ans[u]+=(long long)(n-sum-1)*(sum+1)+(n-1);//加上剩余部分
    else 
        ans[u]=2*(n-1); 
}

int main(){
    init();
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        if(u==v)continue;//规定无重边 
        addedge(u,v);
        addedge(v,u);
    }
    tarjan(1);
    for(int i=1;i<=n;i++)
        printf("%lld
",ans[i]); 
    
}
原文地址:https://www.cnblogs.com/zsben991126/p/10456131.html