zoukankan      html  css  js  c++  java
  • [ BZOJ1123 ] BLO(tarjan点双连通分量)

    题干:

      Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。

    题解:

      本题要求求去掉第 i 个点后消失了多少对节点。(关于加减节点的问题就容易想到点双连通分量

      拿到这道题,作者首先想到的就是每去掉一个点,就会少(n-1)对点。

      后来看样例发现:好像这个节点对是有顺序的,那就是 2*(n-1)对点。

      作者后来转念一想,这不是 tarjan 专题吗?不可能出个这么水的题。。。

      于是又手模了几个样例,才发现刚才想的也对:(但太片面了)  

      1、若现在这个节点为 x ,且它并不是割点,那么它只能是环里的一个不是割点的点,答案就是2*(n-1)

    (割点是指强联通分量中的一个特殊的点,不在环中的单个点也为割点)

      2、若现在这个节点 x 是割点,那么它的消失一定会构造出森林,那么消失的节点对也就不止2*(n-1)对 。答案应该是每一棵树的大小乘上原图上其余部分的大小,最后再乘2。(不同顺序也算)

    ans+=2*siz[to]*(n-siz[to])*1ll;   (错解)

      于是作者便高高兴兴地开始打代码 —— 0分。。。

      为什么呢?  

      上面那个式子将我们枚举的那个断点算重了好多次。不可以乘二。。。

      我们尝试换一种思路:

    ans+=siz[to]*(n-siz[to])*1ll;

      (虽然就少了'*2' ,但至少不会算重啊。。。)

      其实 tarjan 就是基于 dfs 而衍生出来的算法。dfs有一个特性,它在遍历一张图时,不可遍历重复的点(遍历树时,不可遍历其父节点),否则就会死循环。而这道题,我们需要知道这个节点 x 以上部分的大小,从而将这以上部分也作为一棵子树进行统计答案。而 tarjan(dfs) 却无法访问这棵“子树”,这就造成我们少计算了一种情况。统计答案:

    ans+=(sum+1)*(n-sum-1) + (n-1)

      其中的 sum 为真正的子树和(其实特别好维护,就是dfs求),我用(n-sum)就间接地求出了这个节点上面的“子树”。为什么sum要减一加一呢?我们再回过头去看,在统计每一个真正的子树所做的贡献时,我们将枚举的断点归到了其余的部分,而不是这棵子树,所以这种情况也需要同样处理。

      那 ‘ +(n-1) ’是怎么回事呢?我们再看一下这个算法,所有的子树都考虑了节点对 顺序的情况(每两个子树或直接或间接地乘了两遍),但相对我们枚举的切点,只乘了一遍,所以要补救一下。

      最后一步就是求割点了。(板子)

    1     opt=0;
    2     if(dfn[to]>=low[x]){
    3         tarjan(to);
    4         low[x]=min(low[x],low[to]);
    5         if(low[x]>=dfn[to]) opt++;
    6         if(x!=root||opt>1)  cut[x]=1;
    7     }
    8     else low[x]=min(low[x],dfn[to]);    

    (注意一下,针对有向图的tarjan,需要判断是否入队;而无向图就不用)

    Code:

     1 #include<cstdio>
     2 #include<cstring>
     3 #define $ 100010
     4 using namespace std;
     5 int m,n,first[$],tot,dfn[$],low[$],tar,siz[$];
     6 long long ans[$];
     7 bool cut[$];
     8 struct tree{    int to,next;    }a[$*10];
     9 inline int min(int x,int y){    return x<y?x:y;    }
    10 inline void add(int x,int y){
    11     if(x==y) return;
    12     a[++tot]=(tree){    y,first[x]    };
    13     first[x]=tot;
    14     a[++tot]=(tree){    x,first[y]    };
    15     first[y]=tot;
    16 }
    17 inline void tarjan(int x){
    18     low[x]=dfn[x]=++tar; siz[x]=1;
    19     int opt=0,sum=0;
    20     for(register int i=first[x];i;i=a[i].next){
    21         int to=a[i].to;
    22         if(!dfn[to]){
    23             tarjan(to);
    24             siz[x]+=siz[to];
    25             low[x]=min(low[x],low[to]);
    26             if(low[to]>=dfn[x]){
    27                 opt++;
    28                 ans[x]+=1ll*siz[to]*(n-siz[to]);
    29                 sum+=siz[to];
    30             }
    31             if(x!=1||opt>1) cut[x]=1;
    32         }
    33         else low[x]=min(low[x],dfn[to]);
    34     }
    35     if(cut[x]) ans[x]+=1ll*(n-sum-1)*(sum+1)+1ll*(n-1);
    36     else       ans[x]=1ll*2*(n-1);
    37 }
    38 signed main(){
    39     scanf("%d%d",&n,&m);
    40     for(register int i=1,x,y;i<=m;++i) scanf("%d%d",&x,&y),add(x,y);
    41     tarjan(1);
    42     for(register int i=1;i<=n;++i) printf("%lld
    ",ans[i]);
    43 }
    View Code
    越努力 越幸运
  • 相关阅读:
    Linux文件管理
    网络层基础
    引导与服务控制实验
    交换机基础
    计算机网络基础
    计算机视觉 牛人主页 Hanson
    CV codes代码分类整理合集(http://www.sigvc.org/bbs/thread7211.html) Hanson
    机器学习中的相似性度量 (附matlab代码) Hanson
    机器学习问题方法总结 Hanson
    支持向量机很全的代码和数据集 Hanson
  • 原文地址:https://www.cnblogs.com/OI-zzyy/p/11182990.html
Copyright © 2011-2022 走看看