• bzoj 3569: DZY Loves Chinese II


    链接 3569: DZY Loves Chinese II

    • 题目大意:给出一张(n)个点(m)条边的无向图,进行(q)次询问,问删掉某(k)条边后图是否联通,强制在线。
    • (N≤100000 M≤500000 Q≤50000 1≤K≤15)
    • 先考虑一下离线怎么做:
    • (cdq)分治。
    • 首先把所有没有影响的边都建出来
    • 分治过程:
    • 1、把左边没有右边有的边建出来
    • 2、分治左边
    • 3、把并查集恢复至初始的样子
    • 4、把右边没有左边有的边建出来
    • 5、分治右边
    • 虽然每次(cdq)的过程中,都暴力判断了每个询问中的边集合的划分情况,但是复杂度是类似于线段树递归的
    • 所以总复杂度还是(O(qklogq))
    • 有个细节就是,如何将并查集恢复至初始的样子?
    • 每当一个点的父亲被修改时,将它和它的父亲入栈,每次只需要记录一下当前过程对应在栈的哪个位置即可
    • 这样就顺带把[Ahoi2013]连通图切掉了
    • 强制在线怎么做?
    • 我们首先可以求出一棵生成树,然后边就有树边和非树边。
    • 对于一条非树边,我们给它赋一个随机的权值。
    • 然后对于每条树边,它的权值就是所有覆盖这条树边的非树边的权值的异或和。
    • 具体如何搞出树边的权值呢:
    • 树上差分一下,在每条非树边的两端打上标记,树边的权值就是y的子树的异或和。
    • 当然你想写一个树剖也可以
    • 这样我们可以发现,如果这条树边和所有覆盖它的非树边都删除了,就一定不会联通,而都删除代表选出的这些边的异或和为0。
    • 那么问题变成了每次给出一个边集问是否有某个子集的异或和为0。
    • 线性基维护一下即可。
    • 复杂度(O(n+qklog(1e9)))
    #include<bits/stdc++.h>
    #define R register int
    #define ll long long
    #define uLL unsigned long long 
    using namespace std;
    const int N=2000001;
    const int M=1000001;
    int n,m,cnt,vis[N],nt[M],to[M],hd[N],p,flag;
    uLL num[M],vl[N],Bas[35];
    struct ed{int u,v,us;}G[M];
    void link(R f,R t){nt[++cnt]=hd[f],to[cnt]=t,hd[f]=cnt;}
    uLL rnd() { return (((uLL)rand())<<32)^((uLL)rand()<<16)^rand(); }
    int gi(){
        R x=0,k=1;char c=getchar();
        while((c<'0'||c>'9')&&c!='-')c=getchar();
        if(c=='-')k=-1,c=getchar();
        while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
        return x*k;
    }
    void Dfs1(R i,R e){
    	vis[i]=1;
    	for(R k=hd[i];k;k=nt[k])
    		if(!vis[to[k]])
    			G[k>>1].us=1,Dfs1(to[k],i);
    }
    void Dfs2(R i){
    	vis[i]=1;
    	for(R k=hd[i];k;k=nt[k])
    		if(!vis[to[k]]){
    			Dfs2(to[k]),vl[k>>1]=num[to[k]];
    			num[i]^=num[to[k]];
    		}
    }
    void ins(R x){
    	for(R j=0;j<=30;++j){
    		(!x)?flag=1:0;
    		if((1<<j)&x){
    			if(!Bas[j]){Bas[j]=x;return;}
    			else x^=Bas[j];
    		}
    	}
    }
    int main(){
    	freopen("chi.in","r",stdin);
    	freopen("chi.out","w",stdout);
    	srand(time(NULL));
    	n=gi(),m=gi(),cnt=1;
    	for(R i=1;i<=m;++i){
    		G[i].u=gi(),G[i].v=gi();
    		link(G[i].u,G[i].v),link(G[i].v,G[i].u);
    	}
    	Dfs1(1,0);
    	for(R i=1;i<=m;++i)
    		if(!G[i].us){
    			vl[i]=rnd();
    			num[G[i].u]^=vl[i],num[G[i].v]^=vl[i];
    		}
    	memset(vis,0,sizeof(vis));
    	Dfs2(1);R u=0,q=gi(),v;
    	while(q--){
    		p=gi(),flag=0,memset(Bas,0,sizeof(Bas));
    		for(R j=1;j<=p;++j)v=gi()^u,ins(vl[v]);
    		if(!flag)u++,puts("Connected");
    		else puts("Disconnected");
    	}
        return 0;
    }
    
    
  • 相关阅读:
    oracle中number数据类型简单明了解释
    计算机专业课程体系介绍(含学习顺序)
    浮点数的二进制表示
    C语言中为什么float型数据的范围是3.4E-38~3.4E+38
    C语言学习笔记
    近期学习计划
    二进制、八进制、十进制、十六进制之间转换
    MySQL 字段值为NULL,PHP用json转换,传给js,显示null
    写出float x 与“零值”比较的if语句——一道面试题分析
    BOOL,int,float,指针变量 与“零值”比较的if语句
  • 原文地址:https://www.cnblogs.com/Tyher/p/9827421.html
Copyright © 2020-2023  润新知