随机算法瞎练BZOJ3237&3563&3569三倍经验题
随机方法真的好骚啊O(∩_∩)O~
最早的时候miaom提出一个奇怪的东西:
判断一个数列中是否有0/1/2个数出现奇数次
对每个数赋一个随机权值,异或乱搞,对于判2的情况用一个(可能类似线性基的)方法做一下
然后我就开始瞎bb:能不能在边或点上赋一些随机权,做一些图论的判定性问题
(*^▽^*)判断无向图联通
首先考虑建一棵生成树,则任何破坏连通性的操作都需要破坏这棵树上的边
要使图不联通,肯定有一棵子树掉下来了
而子树掉下来的条件是它的根到根的父亲的边断开,且连接子树和树外点的非树边断开
这是个很好的性质,可以用来搞事情
对于树外的边都赋上一个随机权值,每个点的权值就是与之相连的非树边的权值异或和
树上边的权值是它下面的子树所有点的异或和
那么一来,一些边(恰好)切下一个子树的条件就是异或和=0
不难发现每次切下的边数很少,3237中只有4,不妨枚举所有子集,看看是否恰好切割
剩下两题有15,不妨用线性基维护,能组合出0的条件是一个数没用(扫到最后还没有被加入线性基)
没啦
made这破bzoj不兹磁time(0)还报RE,害我调了一下午
这里只贴出3569的代码(前两个没保存,直接改上去了)
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n,m,p,q,E,Q; 4 struct edge 5 { 6 int from,to; 7 } e[1000001]; 8 struct bas 9 { 10 int a[32]; 11 bool over; 12 bas() 13 { 14 for(int i=0;i<=31;i++) 15 a[i]=0; 16 over=0; 17 } 18 void add(int x) 19 { 20 if(over) return; 21 for(int i=31;i>=0;i--) 22 if(x>>i) 23 if(a[i]) x^=a[i]; 24 else 25 { 26 a[i]=x; 27 return; 28 } 29 over=1; 30 } 31 } ret; 32 int w[1000001],wei[1000001],fa[1000001]; 33 int nex[1000001],fir[1000001]; 34 bool vis[1000001]; 35 void build(int now,int fat) 36 { 37 fa[now]=fat;vis[now]=1; 38 for(int i=fir[now];i;i=nex[i]) 39 if(!vis[e[i].to]) 40 build(e[i].to,now); 41 } 42 int dfs(int now) 43 { 44 for(int i=fir[now];i;i=nex[i]) 45 if(fa[e[i].to]==now) 46 w[now]^=dfs(e[i].to); 47 return w[now]; 48 } 49 void add(int x,int y) 50 { 51 e[++E].from=x;e[E].to=y;nex[E]=fir[x];fir[x]=E; 52 e[++E].from=y;e[E].to=x;nex[E]=fir[y];fir[y]=E; 53 } 54 int main() 55 { 56 scanf("%d%d",&n,&m); 57 for(int i=1;i<=m;i++) 58 scanf("%d%d",&p,&q),add(p,q); 59 build(1,0); 60 srand(2333); 61 for(int i=1;i<=E;i+=2) 62 if(fa[e[i].from]!=e[i].to && fa[e[i].to]!=e[i].from) 63 { 64 wei[i]=rand()*32768+rand(); 65 w[e[i].from]^=wei[i]; 66 w[e[i].to]^=wei[i]; 67 } 68 dfs(1); 69 70 for(int i=1;i<=E;i+=2) 71 if(fa[e[i].from]==e[i].to) 72 wei[i]=w[e[i].from]; 73 else 74 if(fa[e[i].to]==e[i].from) 75 wei[i]=w[e[i].to]; 76 77 scanf("%d",&Q); 78 int key=0; 79 for(int i=1;i<=Q;i++) 80 { 81 if(i==5) 82 int e=1; 83 scanf("%d",&p); 84 // p^=key; 85 ret=bas(); 86 for(int j=1;j<=p;j++) 87 scanf("%d",&q),q^=key, 88 ret.add(wei[q*2-1]); 89 if(!ret.over) key++; 90 puts(ret.over?"Disconnected":"Connected"); 91 } 92 return 0; 93 }