博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ3237】【AHOI2013】连通图 [CDQ分治]
阅读量:5093 次
发布时间:2019-06-13

本文共 3440 字,大约阅读时间需要 11 分钟。

连通图

Time Limit: 20 Sec  Memory Limit: 512 MB
[][][]

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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
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("\n");154 }155 }
View Code

 

转载于:https://www.cnblogs.com/BearChild/p/6436030.html

你可能感兴趣的文章
站立会议08(冲刺2)
查看>>
url查询参数解析
查看>>
http://coolshell.cn/articles/10910.html
查看>>
[转]jsbsim基础概念
查看>>
Thrift Expected protocol id ffffff82 but got 0
查看>>
【2.2】创建博客文章模型
查看>>
【3.1】Cookiecutter安装和使用
查看>>
【2.3】初始Django Shell
查看>>
Linux(Centos)之安装Redis及注意事项
查看>>
bzoj 1010: [HNOI2008]玩具装箱toy
查看>>
Kotlin动态图
查看>>
从零开始系列之vue全家桶(1)安装前期准备nodejs+cnpm+webpack+vue-cli+vue-router
查看>>
ASP.NET缓存 Cache之数据缓存
查看>>
bzoj3529: [Sdoi2014]数表
查看>>
SSH三大框架 整合必备jar包
查看>>
什么是电子商务?电子商务面临的几个关键问题及解决办法?电子商务的核心是什么?B2C电子商务运营的核心是什么 ?...
查看>>
Jsp抓取页面内容
查看>>
AJAX与servlet的组合,最原始的
查看>>
大三上学期软件工程作业之点餐系统(网页版)的一些心得
查看>>
MySQL 数据表修复及数据恢复
查看>>