zoukankan      html  css  js  c++  java
  • 题解-bzoj3569 DZY Loves Chinese II

    Problem

    bzoj

    题意概要:给定(n)(m)边无向连通图,(Q)次询问删除(k)条边后是否仍然连通,强制在线

    Solution

    半年前考到过这类题目(询问删除任意两条边使得图不连通的方案数),当时就整场怼这道题,虽然最后怼出来了但其他题根本没拿分。当时觉得这个解法好新颖,特别兴奋自己想出来了,然后做到这道题才发现这类方法都是套路/(ㄒoㄒ)/~~

    有关图的连通基本都是建生成树,如果图不连通了,则只有可能切断了树上的一条边后将所有跨越该树边的非树边全部切断

    发现不好维护,于是用到这类题的套路,给每条非树边随机一个权值,将对应的树上路径全部(xor)上这个权值,则询问时只要看看存不存在非树边集合使得集合权值异或和等于某条树边,然后套用线性基即可

    还是做题做得多,套用之前题目的做法就能很容易想到,不像上次考试那样要现场想算法

    Code

    #include <bits/stdc++.h>
    typedef long long ll;
    
    inline void read(int&x){
    	char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
    	while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
    }
    
    const int N=101000,M=1001000,K=50;
    const ll lim=1ll<<K;
    struct Edge{int v,id,nxt;}a[M];
    struct edge{int l,r;ll w;bool tree;}e[M];
    int head[N],dep[N],fa[N];
    int n,m,_;ll tag[N],d[60];
    
    void dfs(int x,int las){
    	for(int i=head[x];i;i=a[i].nxt)
    		if(a[i].v!=las)
    			if(!dep[a[i].v]){
    				dep[a[i].v]=dep[x]+1;
    				fa[a[i].v]=x;
    				dfs(a[i].v,x);
    				e[a[i].id].tree=true;
    			}else if(dep[a[i].v]<dep[x]){
    				ll rd=(ll)rand()*rand()%lim;
    				tag[x]^=rd,tag[a[i].v]^=rd;
    				e[a[i].id].w=rd;
    			}
    }
    
    void tag_up(int x){
    	for(int i=head[x];i;i=a[i].nxt)
    		if(dep[a[i].v]==dep[x]+1){
    			tag_up(a[i].v);
    			e[a[i].id].w=tag[a[i].v];
    			tag[x]^=tag[a[i].v];
    		}
    }
    
    int main(){
    	read(n),read(m);
    	for(int i=1;i<=m;++i){
    		read(e[i].l),read(e[i].r);
    		e[i].tree=false;
    		a[++_].v=e[i].r,a[_].nxt=head[e[i].l],a[_].id=i,head[e[i].l]=_;
    		a[++_].v=e[i].l,a[_].nxt=head[e[i].r],a[_].id=i,head[e[i].r]=_;
    	}
    	dep[1]=1,dfs(1,0);
    	tag_up(1);
    	
    	int Q,k,c[20],xor_val=0;
    	read(Q);while(Q--){
    		read(k);
    		for(int i=1;i<=k;++i){
    			read(c[i]);c[i]^=xor_val;
    			if(!e[c[i]].tree){
    				ll x=e[c[i]].w;
    				for(int j=K;~j;--j)
    					if(x&(1<<j))
    						if(d[j])x^=d[j];
    						else {d[j]=x;break;}
    			}
    		}
    		bool cut=false;
    		for(int i=1;i<=k;++i)
    			if(e[c[i]].tree){
    				ll x=e[c[i]].w;
    				for(int j=K;~j;--j)
    					if(x&(1<<j))x^=d[j];
    				if(!x){cut=true;break;}
    			}
    		puts(cut?"Disconnected":"Connected");
    		xor_val+=(!cut);
    	}return 0;
    }
    
  • 相关阅读:
    寄存器详解
    Sleep(0)的妙用
    源码分析之Dictionary笔记
    ASP.NET Core框架的本质
    Dictionary实现(收藏的)
    微软的判断一个数是不是质数的算法
    C#性能优化:延迟初始化Lazy
    C#3 分部方法,简单标记一下
    单例下并发的情况下访问私有变量的一个典型问题
    BeforeFieldInit的小叙
  • 原文地址:https://www.cnblogs.com/penth/p/10206877.html
Copyright © 2011-2022 走看看