zoukankan      html  css  js  c++  java
  • 【BZOJ3237】【AHOI2013】连通图 [CDQ分治]

    连通图

    Time Limit: 20 Sec  Memory Limit: 512 MB
    [Submit][Status][Discuss]

    Description

      

    Input

      

    Output

      

    Sample Input

      4 5
      1 2
      2 3
      3 4
      4 1
      2 4
      3
      1 5
      2 2 3
      2 1 2

    Sample Output

      Connected
      Disconnected
      Connected

    HINT

      N<=100000 M<=200000 K<=100000

    Main idea

      给定一张无向联通图,询问删除掉若干条边后图是否联通,多次询问。

    Solution

      首先我们看到删边判联通,第一反应想到了LCT,由于图不是一棵树,无法用LCT实现,那么我们否决掉了动态维护的方法。
      根据可以离线询问这一特征来思考如何操作,发现k(询问数)<=100000,显然是log级别的做法,结合可离线的特征,这时候只剩下了对于所有询问一起进行操作的方法 ,现在我们得出了算法:CDQ分治
      发现直接删边操作较为困难,我们逆向思维,考虑如何在一个空的图上加边
      先考虑只有两个询问的情况,假定我们的询问删边集合为A,B,那么显然想到了先把不在A中并且不在B中边加入(这时称其为状态一),然后分开处理,先加入不在A中但是在B中的边,判下是否联通就得到了A中的答案,然后回到状态一,加入不在B中在A中的边,判断一下得到了B的答案
      然后基于这样的整个思路,我们考虑如何将两个集合拓展到多个集合
      立马想到了分治,对于所有集合分治使其类同于A,B两种“大集合”,然后继续分治,最后必然可以归于仅有两个小集合的情况,然后向上回溯即可。加边用并查集加入即可。
      我们来整理一下CDQ分治的思路:
        1、加入不在左区间但在右区间的边;
        2、对于左区间继续分治;
        3、回到上一层的状态(在分治的时候记录并查集中改变了的父子关系,暴力修改回去即可)
        4、加入不在右区间但在左区间的边;
        5、对于右区间继续分治;
        ……
      最后判断是否联通的时候又发现一开始的整张图是处于连通状态的,所以我们只要判断删掉的边的端点是否连通即可。

    Code

      1 #include<iostream>  
      2 #include<algorithm>  
      3 #include<cstdio>  
      4 #include<cstring>  
      5 #include<cstdlib>  
      6 #include<cmath>
      7 #include<queue>
      8 using namespace std;  
      9        
     10 const int ONE=200005;
     11  
     12 int n,m,Bian;
     13 int fat[ONE],cnt;
     14 int PD[ONE];
     15 int Ans[ONE]; 
     16  
     17 struct power
     18 {
     19         int x,y;
     20 }a[ONE*2],q[ONE*100];
     21  
     22 struct point
     23 {
     24         int c;
     25         int b[5];
     26 }quey[ONE];
     27  
     28 int get()
     29 {
     30         int res,Q=1;    char c;
     31         while( (c=getchar())<48 || c>57)
     32         if(c=='-')Q=-1;
     33         if(Q) res=c-48; 
     34         while((c=getchar())>=48 && c<=57) 
     35         res=res*10+c-48; 
     36         return res*Q; 
     37 }
     38  
     39 int Find(int x)
     40 {
     41         if(x!=fat[x])
     42         {
     43             q[++cnt].x=x;   q[cnt].y=fat[x];
     44             fat[x]=Find(fat[x]);
     45         }
     46         return fat[x];
     47 }
     48  
     49 void Un(int x,int y)
     50 {
     51         int f1=Find(x);
     52         int f2=Find(y);
     53         if(f1!=f2)
     54         {
     55             q[++cnt].x=f2;  q[cnt].y=fat[f2];
     56             fat[f2]=f1;
     57         }
     58 }
     59  
     60 int Get_pd(int l)
     61 {
     62         int pd=1;
     63         for(int i=1;i<=quey[l].c;i++)
     64         {
     65             int j=quey[l].b[i];
     66             if(Find(a[j].x) != Find(a[j].y))
     67             {
     68                 pd=0;
     69                 break;  
     70             }
     71         }
     72         return pd;
     73 }
     74  
     75 void Mark(int l,int r,int t)
     76 {
     77         for(int i=l;i<=r;i++)
     78         {
     79             for(int j=1;j<=quey[i].c;j++)
     80             PD[quey[i].b[j]]=t;
     81         }
     82 }
     83  
     84 void Add(int l,int r)
     85 {
     86         for(int i=l;i<=r;i++)
     87         {
     88             for(int j=1;j<=quey[i].c;j++)
     89             {
     90                 int num=quey[i].b[j];
     91                 if(PD[num]) continue;
     92                 Un(a[num].x,a[num].y);
     93             }
     94         }
     95 }
     96  
     97 void Back(int Now_cnt)
     98 {
     99         for(;cnt>Now_cnt;cnt--) 
    100         fat[q[cnt].x]=q[cnt].y;
    101 }
    102  
    103 void CDQ(int l,int r)
    104 {
    105         if(l==r)
    106         {
    107             Ans[l]=Get_pd(l);
    108             return;
    109         }
    110          
    111         int Now_cnt=cnt;
    112         int mid=(l+r)/2;
    113         Mark(l,mid,1); Add(mid+1,r); Mark(l,mid,0);
    114         CDQ(l,mid);
    115          
    116         Back(Now_cnt);
    117         Mark(mid+1,r,1); Add(l,mid); Mark(mid+1,r,0);
    118         CDQ(mid+1,r);
    119 }
    120  
    121  
    122 int main()
    123 {
    124         n=get();    Bian=get();
    125         for(int i=1;i<=n;i++) fat[i]=i;
    126         for(int i=1;i<=Bian;i++)
    127         {
    128             a[i].x=get();   a[i].y=get();
    129         }
    130          
    131         m=get();
    132         for(int i=1;i<=m;i++)
    133         {
    134             quey[i].c=get();
    135             for(int j=1;j<=quey[i].c;j++)
    136             quey[i].b[j]=get();
    137         }
    138          
    139         Mark(1,m,1);
    140         for(int i=1;i<=Bian;i++)
    141         {
    142             if(PD[i]) continue;
    143             Un(a[i].x,a[i].y);
    144         }
    145         Mark(1,m,0); cnt=0;
    146          
    147         CDQ(1,m);
    148          
    149         for(int i=1;i<=m;i++)
    150         {
    151             if(Ans[i]) printf("Connected");
    152             else printf("Disconnected");
    153             printf("
    ");
    154         }
    155 }
    View Code

     

  • 相关阅读:
    技嘉H81M-DS2 主板安装 XP方法,及网卡驱动安装
    XCode5无法设置Deployment Target的解决办法
    CALayer的contentsRect
    有道词典for mac不能取词解决方案
    应用沙盒(Application Sandbox)
    模态视图控制对象
    UUID(即GUID)
    UIView的endEditing:方法
    让UITableView进入编辑模式
    presentModalViewController方法,present一个透明的viewController,带动画效果
  • 原文地址:https://www.cnblogs.com/BearChild/p/6436030.html
Copyright © 2011-2022 走看看