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;
}

posted @ 2018-10-21 22:35  Tyher  阅读(273)  评论(0编辑  收藏  举报