zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    二选一的痛定思痛
    .net 代码混淆原理性实践
    什么是 RSS?
    ViewEngine 深入解析与应用实例 {转}
    C#访问修饰符及各种元素的访问修饰符的默认值
    [转]基于VS.NET的自定项目模板研究
    刘若鹏
    System.Configuration 和Connection
    Page.Master.FindControl?还是Page.FindControl?
    模板页中的链接
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/11510717.html
Copyright © 2011-2022 走看看