bzoj3237 连通图

题意:在一个无向图上每次删去少量边,问是否还连通?

标程:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int read()
 4 {
 5     int x=0;char ch=getchar();
 6     while (ch<'0'||ch>'9') ch=getchar();
 7     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
 8     return x;
 9 }
10 const int N=200005;
11 int cnt,head[N],n,m,c,k,w,val[N],u[N],v[N],sum,fl,vis[N],base[32],fa[N];
12 map<int,int> mp;
13 struct node{int to,next,w;}num[N*2];
14 void add(int x,int y,int w)
15 {num[++cnt].to=y;num[cnt].next=head[x];num[cnt].w=w;head[x]=cnt;}
16 int ins(int x)
17 {
18     for (int i=30;i>=0;i--)
19      if ((x>>i)&1)
20        if (!base[i]) return base[i]=x,1;
21        else x^=base[i];
22     return 0;
23 } 
24 void dfs(int x)
25 {
26     vis[x]=1;
27     for (int i=head[x];i;i=num[i].next)
28     {
29         if (!vis[num[i].to]) fa[num[i].to]=x,dfs(num[i].to),val[x]^=val[num[i].to];
30         else if (num[i].to!=fa[x]) val[x]^=num[i].w;
31     } 
32 }
33 int main()
34 {
35     srand(2333);
36     n=read(),m=read();
37     for (int i=1;i<=m;i++) u[i]=read(),v[i]=read(),w=rand()*131,add(u[i],v[i],w),add(v[i],u[i],w);
38     dfs(1); k=read();
39     for (int i=1;i<=n;i++)
40       if (!vis[i]) {
41           for (int j=1;j<=k;j++) puts("Disconnected");
42           return 0;
43       }
44     while (k--)
45     {
46         c=read();memset(base,0,sizeof(base));fl=1;
47         for (int i=1;i<=c;i++) 
48         {
49             int x=read();
50             if (fa[u[x]]==v[x]) fl&=ins(val[u[x]]);
51             else if(fa[v[x]]==u[x]) fl&=ins(val[v[x]]);
52             else fl&=ins(num[x*2].w);
53         }
54         puts(fl?"Connected":"Disconnected");
55      }
56     return 0;
57 } 
View Code

 

题解:随机权值+断开生成子树+线性基/cdq分治

对每一条边随机一个权值。建一棵生成树,如果要切去一个子树的话必须把子树连到其父亲的根切掉,以及子树中所有的返祖边。

对于每一个节点保存子树中所有返祖边的异或和。删去的边,如果是非树边,就把其权值扔进线性基;是树边,扔进其保存的子树异或和。

那么如果某个时刻某权值已经可以在线性基中被线性表示,那么说明Disconnected。

随机权值这个东西可以用来处理序列上出现奇数次的元素是否恰好有0/1/2个,某条路径是否被全部经过,图联通的判定等等。

 

cdq分治

转载于:https://www.cnblogs.com/Scx117/p/9152242.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值