【POI2008】BLO-Blockade (图的割点)

传送门

Solution:

图上的点分为两种:

1.隔离后对图的连通性有影响的
2.没有影响的

情况2是很简单的,也就是样例中的1,2,5点,易知答案是(n-1)*2

情况1,其实就是图的割点

我们考虑如何求图的割点——

先回顾low,dfn的定义

定义 DFN(u)为结点 u 搜索的次序编号(时间戳), Low(u)为 u 或 u 的子树(经过最多一条
后向边或栈中横叉边) 能够回溯到的最早的栈中结点的次序号。

(后向边: 与 DFS 方向相反, 从某个结点指向其某个祖先的边
横叉边: 从某个结点指向搜索树中另一子树中的某结点的边)

运用tarjan算法,.当一个点的某一个孩子的low>=此点的dfn时,这个点就是割点。因为对于一个点now,会把整个图分为两部分,一部分搜索过,一部分没有,如果now的一个孩子的low大于了dfn[now],说明这个孩子无法回到已经搜索过的那一部分。若割去now,那么因为这个特殊的孩子,图就无法连通。

学会如何求割点后,我们考虑如何记录割点的答案

我们对于一个点出去他所到达的和能到达它的之外。剩下的就是他相连的联通块之间的相连的了。

我们在来处理这一部分。在tarjan里面,我们处理出这个点所能到达且是他的子树的的联通块的大小,这样他的父亲树的大小就为总点数减去这个点减去他的子树的大小,即n-1-

size[i] i为当前点。 这样我们又能得知他们之间不能相连的点数就是他的父亲节点内的个数*塔子树节点内的个数、。即ans【i】=t*(n-t-1) t=size[i] 这样我们求出了从该点外不能互

相到达的对数
#include<bits/stdc++.h>
#define N 100005
#define M 500005
typedef long long ll;
using namespace std;
ll n,m,first[N],tot,dfn[N],low[N],sign,size[N],ans[N];
struct node
{
    ll to,next;
}edge[2*M];
inline void addedge(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=first[x];
    first[x]=tot;
}
inline void dfs(ll now,ll fa)
{
    dfn[now]=low[now]=++sign;
    size[now]=1;
    ll k=0;
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(dfn[vis]==0)
        {
            dfs(vis,now);
            low[now]=min(low[vis],low[now]);
            size[now]+=size[vis];
            if(low[vis]>=dfn[now])
            {
                ans[now]+=k*size[vis];  //可能分为多个部分 
                k+=size[vis];
            }
        }
        else if(vis!=fa)//无向图不可能有横叉边 
        {
            low[now]=min(low[now],dfn[vis]);
        }
    }
    ans[now]+=k*(n-k-1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL),cout.tie(NULL);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        ll x,y;
        cin>>x>>y;
        addedge(x,y);
        addedge(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++)   cout<<(ans[i]+n-1)*2<<endl;
    return 0;
}

转载于:https://www.cnblogs.com/Patrickpwq/articles/9436122.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值