BZOJ 3569 DZY Loves Chinese II 树上差分+线性基

时间:2022-03-23 18:16:20

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3569

Description

神校XJ之学霸兮,Dzy皇考曰JC。
摄提贞于孟陬兮,惟庚寅Dzy以降。
纷Dzy既有此内美兮,又重之以修能。
遂降临于OI界,欲以神力而凌♂辱众生。
 
今Dzy有一魞歄图,其上有N座祭坛,又有M条膴蠁边。
时而Dzy狂WA而怒发冲冠,神力外溢,遂有K条膴蠁边灰飞烟灭。
而后俟其日A50题则又令其复原。(可视为立即复原)
然若有祭坛无法相互到达,Dzy之神力便会大减,于是欲知其是否连通。

Input

第一行N,M,接下来M行x,y:表示M条膴蠁边,依次编号;接下来一行Q,接下来Q行:每行第一个数K而后K个编号c1~cK,表示K条边,编号为c1~cK。
为了体现在线,c1~cK均需异或之前回答为连通的个数。

Output

对于每个询问输出:连通则为‘Connected’,不连通则为‘Disconnected’(不加引号)

Sample Input

5 10
2 1
3 2
4 2
5 1
5 3
4 1
4 3
5 2
3 1
5 4
5
1 1
3 7 0 3
4 0 7 4 6
2 2 7
4 5 0 2 13

Sample Output

Connected
Connected
Connected
Connected
Disconnected

HINT

N≤100000,M≤500000,Q≤50000,1≤K≤15,数据保证没有重边与自环

Tip:请学会使用搜索引擎

题意概述:

  给出一张图,每次假设删除图上K条边,询问图是否连通。

分析:

  这操作还是很厉害的......

  对于图的问题可以借助和图有关的树来分析。

  借助DFS树,我们发现当我们删除一些边的时候,只有我们把某条树边以及所有跨越它的非树边删除掉之后这个图就不连通了。

  那么我先现在需要判断给出的边中有没有这样的一些边出现。如果有,那么图就不连通,否则就依旧连通。

  怎么判断呢?想到异或,当一些线性相关的数字一起出现的时候,它们的其中一些异或和为0。对于每一条非树边,将其随机一个权值,然后对其跨越的所有边异或上它的权值。每一次询问的时候取出来求线性基,如果线性基插入过程中有数字变成了0,说明给出的数字不是线性不相关。

  因为K<=15,所以说可以直接用rand()函数(实在不放心可以手动随机二进制位)。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int maxn=;
const int maxm=; int N,M,Q;
struct edge{ int to,next; }E[maxm<<];
int first[maxn],np,fl[maxn],delt[maxn],dfn[maxn],dfs_clock,w[maxm],vis[maxn];
struct Linear_Base{
static const int up=;
int b[up];
void init(){ memset(b,,sizeof(b)); }
bool ins(int x){
for(int i=up-;i>=;i--) if((<<i)&x){
if(!b[i]) { b[i]=x; break; }
else x^=b[i];
}
return x!=;
}
}lb; void add_edge(int u,int v)
{
E[++np]=(edge){v,first[u]};
first[u]=np;
}
void data_in()
{
scanf("%d%d",&N,&M);
int x,y;
for(int i=;i<=M;i++){
scanf("%d%d",&x,&y);
add_edge(x,y); add_edge(y,x);
}
scanf("%d",&Q);
}
void DFS(int i,int fp)
{
dfn[i]=++dfs_clock,fl[i]=fp;
for(int p=first[i];p;p=E[p].next){
if(fp==(p-^)+) continue;
int j=E[p].to;
if(dfn[j]){
if(dfn[j]<dfn[i]){
w[p+>>]=rand()+;
delt[i]^=w[p+>>],delt[j]^=w[p+>>];
}
continue;
}
DFS(j,p);
w[fp+>>]^=w[p+>>];
}
w[fp+>>]^=delt[i];
}
void work()
{
srand();
DFS(,);
int k,x,cnt=;
for(int i=;i<=Q;i++){
scanf("%d",&k);
bool ok=; lb.init();
for(int j=;j<=k;j++){
scanf("%d",&x);
if(ok&&!lb.ins(w[x^cnt])) ok=;
}
if(ok) puts("Connected"),cnt++;
else puts("Disconnected");
}
}
int main()
{
data_in();
work();
return ;
}