• BZOJ3237 [Ahoi2013]连通图


    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

    题目链接:BZOJ3237

    正解:$CDQ$分治

    解题报告:

      考虑直接做的话很难维护图的连通性,$yy$了一下$LCT$似乎可做?

      不过既然是学图分治的就写一发$CDQ$分治吧…

      考虑我把没有被删除过的所有边所连接的点,看做一个点,用并查集合并起来,这样能降低图的规模。

      我每次处理区间为$[l,r]$的询问,当我做$[l,mid]$即左边时,我可以把右边需要删除的边全部加入图中,这样就不会对左边造成影响,然后递归左边,反过来再做一次右边。

      并查集每次需要恢复到历史状态,这只需要用一个栈把修改的地方存下来就可以了。

    //It is made by ljh2000
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #include <string>
    #include <complex>
    #include <bitset>
    using namespace std;
    typedef long long LL;
    typedef long double LB;
    typedef complex<double> C;
    const double pi = acos(-1);
    const int MAXN = 400011;
    const int MAXM = 200011;
    int n,m,Q,ans[MAXN],top,stack[MAXN];
    int size[MAXN],cnt[MAXN],father[MAXN];
    struct edge{ int x,y; }e[MAXM];
    struct ask{ int num,a[5]; }q[MAXN];
    inline int find(int x){ if(father[x]!=x) return find(father[x]);/*!!!*/ return father[x]; }
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void Union(int x,int y){
    	if(size[x]>size[y]) swap(x,y);
    	father[x]=y; size[y]+=size[x]; stack[++top]=x;
    }
    
    inline void recover_stack(int di){
    	int x;
    	while(top>di) {
    		x=stack[top];
    		size[father[x]]-=size[x];
    		father[x]=x;
    		top--;
    	}
    }
    
    inline void CDQ(int l,int r){
    	if(l==r) {
    		if(size[find(1)]==n) ans[l]=1;
    		else ans[l]=0;
    		return ;
    	}
    	int mid=(l+r)>>1,tt=top,x,y;
    	for(int i=mid+1;i<=r;i++) {
    		for(int j=0;j<q[i].num;j++) {
    			cnt[ q[i].a[j] ]--;
    			if(cnt[ q[i].a[j] ]!=0) continue;
    
    			x=e[ q[i].a[j] ].x; y=e[ q[i].a[j] ].y;
    			x=find(x); y=find(y);
    			if(x!=y) Union(x,y);
    		}
    	}
    	CDQ(l,mid);
    	for(int i=mid+1;i<=r;i++)
    		for(int j=0;j<q[i].num;j++)
    			cnt[ q[i].a[j] ]++;
    
    	recover_stack(tt);
    
    	for(int i=l;i<=mid;i++) {
    		for(int j=0;j<q[i].num;j++) {
    			cnt[ q[i].a[j] ]--;
    			if(cnt[ q[i].a[j] ]!=0) continue;
    
    			x=e[ q[i].a[j] ].x; y=e[ q[i].a[j] ].y;
    			x=find(x); y=find(y);
    			if(x!=y) Union(x,y);
    		}
    	}
    	CDQ(mid+1,r);
    	for(int i=l;i<=mid;i++)
    		for(int j=0;j<q[i].num;j++)
    			cnt[ q[i].a[j] ]++;
    
    	recover_stack(tt);
    }
    
    inline void work(){
    	n=getint(); m=getint(); for(int i=1;i<=m;i++) e[i].x=getint(),e[i].y=getint();
    	Q=getint(); int x,y;
    	for(int i=1;i<=Q;i++) {
    		q[i].num=getint();
    		for(int j=0;j<q[i].num;j++) 
    			q[i].a[j]=getint(),cnt[q[i].a[j]]++;
    	}
    	for(int i=1;i<=n;i++) father[i]=i,size[i]=1;
    	for(int i=1;i<=m;i++) {
    		if(cnt[i]==0) {
    			x=e[i].x; y=e[i].y;
    			x=find(x); y=find(y);
    			if(x!=y) {
    				if(size[x]>size[y]) swap(x,y);
    				father[x]=y; size[y]+=size[x];
    			}
    		}
    	}
    
    	CDQ(1,Q);
    
    	for(int i=1;i<=Q;i++)
    		if(ans[i]) puts("Connected");
    		else puts("Disconnected");
    }
    
    int main()
    {
        work();
        return 0;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    mysql执行sql脚本
    Eclipse Memory Analyzer 进行堆转储文件分析
    JAVA字符串格式化-String.format()
    rpm 使用
    md5sum 使用
    Spring Security 初探
    java工厂模式
    Linux 定时任务
    Java Map 知识
    【转】MVC 比较
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6517205.html
Copyright © 2020-2023  润新知