BZOJ1123 || P3469 [POI2008]BLO【Tarjan割点】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/82892325

Time Limit: 10 Sec
Memory Limit: 162 MB

Description

Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。

Input

输入n<=100000 m<=500000及m条边

Output

输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。


题目分析

结点 u u 不是割点,那么去掉他只有 u u 和其他 n 1 n-1 个点不连通
结点 u u 是割点,则需要 将去掉 u u 后产生的连通块两两相乘累加进入答案

Tarjan求割点的过程其实是一个建立搜索树的过程,我们可以从这里入手

假设搜索树上结点 u u 的子节点集合为 { v i } \{v_i\} ,其中有 k k 个点满足其是割点
那么去掉 u u 后将产生至多 k + 2 k+2 个连通块
1.结点 u u 单独在一个连通块
2.搜索树上 u u k k 个满足割点判断的点与他们自己的子树各自构成一个连通块
3.若搜索树上 u u 的子节点数量大于k,那么剩下的点构成一个连通块

由此我们可以在Trajan的过程中顺便记录搜索树上每个子树的大小size[u]
那么去掉 u u 后产生的不连通的有序对数量为

i = 1 k s i z e [ v i ] ( n s i z e [ v i ] ) + 1 ( n 1 ) + ( n 1 i = 1 k s i z e [ v i ] ) ( 1 + i = 1 k s i z e [ v i ] ) \sum_{i=1}^ksize[v_i]*(n-size[v_i])+1*(n-1)+(n-1-\sum_{i=1}^ksize[v_i])*(1+\sum_{i=1}^ksize[v_i])


#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;

lt read()
{
    lt f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

void print(lt x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9)print(x/10);
    putchar(x%10+'0');
}

lt n,m;
lt tot,cnt;
struct node{lt v,nxt;}E[1000010];
lt head[100010];
lt ans[100010];
lt dfn[100010],low[100010];
lt size[100010];
bool cut[100010];
lt rt;

void add(lt u,lt v)
{
    E[++tot].nxt=head[u];
    E[tot].v=v;
    head[u]=tot;
}

void tarjan(lt u)
{
    dfn[u]=low[u]=++cnt; size[u]=1;
    lt flag=0,sum=0;
    for(lt i=head[u];i;i=E[i].nxt)
    {
        lt v=E[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            size[u]+=size[v];
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v])
            {
                flag++;
                ans[u]+=size[v]*(n-size[v]);
                sum+=size[v];
                if(u!=rt||flag>1) cut[u]=true;
            } 
        }
        else low[u]=min(low[u],dfn[v]);
    }
    if(cut[u]) ans[u]+=(n-sum-1)*(sum+1)+n-1;
    else ans[u]=2*(n-1);
}

int main()
{
    n=read();m=read();
    for(lt i=1;i<=m;i++)
    {
        lt u=read(),v=read();
        if(u==v) continue;
        add(u,v);add(v,u);
    }
    
    for(lt i=1;i<=n;i++)
    if(!dfn[i]) rt=i,tarjan(i);
    
    for(lt i=1;i<=n;i++)
    print(ans[i]),printf("\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/82892325