• P3469 [POI2008]BLO-Blockade(tarjan求割点)


    题目地址

    这道题很明显是要寻找割点。

    如果一个点x不是割点,那么删去它之后只会使<x,除x外的其他点>,<除x外的其他点,x>这2*(n-1)个有序对不连通。

    如果x是割点,设si是x的子节点,subtree(si)为以si为根的搜索子树,size[si]为这个子树包含的节点数,t为使x为割点的子节点的个数,那么删去x后,<subtree(si),除subtree(si)的其他点>,<x,除x外的其他点>,<x的所有祖先节点,subtree(x)>这些有序对不连同,那么ans[x]=$sum ^{t}_{k=1}sizeleft[ s_{k} ight] left( n-sizeleft[ s_{k} ight] ight)$ + 1 * (n - 1) + $left( n-1-sum ^{t}_{k=1}sizeleft[ s_{k} ight] ight)$ + $left( 1+sum ^{t}_{k=1}sizeleft[ s_{k} ight] ight)$

    如何判断割点?tarjan算法,如果一个点u,与他的一个子节点v,满足dfn[u] ≤ low[v],那么u就是割点。简单来说,就是点u的有一个子树,子树中所有点能到达的点的最小时间戳都大于等于u的时间戳,说明这个子树中没有点能通过一条边跳过u到达这个子树外的其他点。

    要解决这道题,不妨在tarjan深搜的时候顺便算出子树的size,从而算出答案。

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define MAXN 100010
    #define MAXM 500010
    using namespace std;
    typedef long long LL;
    int n,m;
    int to[MAXM*2],nxt[MAXM*2],head[MAXN],tot=1;
    int dfn[MAXN],low[MAXN],size[MAXN],cut[MAXN],num=0;
    LL ans[MAXN];
    
    void add(int u,int v)
    {
        to[++tot]=v;nxt[tot]=head[u];head[u]=tot;
    }
    
    void tarjan(int u)
    {
        dfn[u]=low[u]=++num;
        size[u]=1;
        int flag=0,sum=0;
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
                size[u]+=size[v];
                if(dfn[u]<=low[v])
                {
                    flag++;
                    ans[u]+=(LL)size[v]*(n-size[v]);
                    sum+=size[v];
                    if(u!=1||flag>1) cut[u]=true;
                }
            }
            else low[u]=min(low[u],dfn[v]);
        }
        if(cut[u]) ans[u]+=(LL)(n-sum-1)*(sum+1)+(n-1);
        else ans[u]=2*(n-1);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,u,v;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        for(int i=1;i<=n;i++) printf("%lld
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    01-NoSQL概述
    SSM快速整合
    C语言指针传参与C++引用传参,以及尾插法建立单链表使用到的引用
    IP地址相关
    二叉树的先序遍历、中序遍历、后序遍历-C语言描述
    华为5G认证练习题2
    华为5G认证练习题
    华为ICT学堂获取练习题及答案
    C++ cin对象的一些方法
    webpack学习笔记2:新建工程
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/11510717.html
Copyright © 2020-2023  润新知