浅谈随机化异或解连通性问题

新套路学习了

1.共价大爷游长沙

Description:

给定一棵n个点的树,支持m次操作:
1.连一条边,删一条边,保证还是树
2.在路径集合中加入一条路径
3.删除集合中的一条路径
4.查询某条边是否被所有路径经过

Hint:

\(n \le 10^5 ,m \le 5*10^5\)

Solution:

思想确实比较巧妙,我们给每条路径两点异或上随机的同一个值

再把Sum异或上这个值,那么查询的边的一个点的子树异或和=Sum时,它就被所有路径经过

由于权值是随机的,这样出错概率极低

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=1e5+5,inf=1e9;
int n,m,cnt,hd[mxn];

inline int read() {
	char c=getchar(); int x=0,f=1;
	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
	return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

struct ed {
	int to,nxt;
}t[mxn<<1];

inline void add(int u,int v) {
	t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}

struct M {
	int x,y,tp;
}p[mxn];

namespace lct {
	int sum,s,sz[mxn],st[mxn],si[mxn],fa[mxn],rev[mxn],val[mxn],ch[mxn][2];
	void push_up(int x) {
		sz[x]=sz[ch[x][0]]^sz[ch[x][1]]^si[x]^val[x];
	}
	void push_down(int x) {
		if(rev[x]) {
			swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
			swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
			rev[x]=0; rev[ch[x][0]]^=1; rev[ch[x][1]]^=1;
		}
	} 
	int isnotrt(int x) {
		return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
	}
	void rotate(int x) {
		int y=fa[x],z=fa[y],tp=ch[y][1]==x;
		if(isnotrt(y)) ch[z][ch[z][1]==y]=x; fa[x]=z;
		ch[y][tp]=ch[x][tp^1]; fa[ch[x][tp^1]]=y;
		ch[x][tp^1]=y; fa[y]=x;
		push_up(y); push_up(x);
	}
	void splay(int x) {
		int tp=x; s=0; st[++s]=tp;
		while(isnotrt(tp)) tp=fa[tp],st[++s]=tp;	
		while(s) push_down(st[s]),--s;
		while(isnotrt(x)) {
			int y=fa[x],z=fa[y];
			if(isnotrt(y)) 
				(ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
			rotate(x);
		}
	}
	void access(int x) {
		for(int y=0;x;x=fa[y=x]) 
			splay(x),si[x]^=(sz[ch[x][1]]^sz[y]),ch[x][1]=y,push_up(x);
	}
	void makert(int x) {
		access(x); splay(x); rev[x]^=1;
		swap(ch[x][0],ch[x][1]);
	}
	void link(int x,int y) {
		makert(x); makert(y);
		fa[x]=y; si[y]^=sz[x]; push_up(y);
	}
	void cut(int x,int y) {
		makert(x); access(y); splay(y);
		fa[x]=ch[y][0]=0; push_up(y);
	}
}
using namespace lct;

int main()
{
	int x,y,u,v,tp,tot=0,opt; opt=read();
	n=read(); m=read(); srand(time(0)); srand(rand());
	for(int i=1;i<n;++i) 
		u=read(),v=read(),link(u,v);
	for(int i=1;i<=m;++i) {
		opt=read(); 
		if(opt==1) {
			u=read(); v=read(); x=read(); y=read();
			cut(u,v); link(x,y);
		}
		else if(opt==2) {
			x=read(); y=read(); tp=rand()%inf+1;
			makert(x); val[x]^=tp; push_up(x); 
			makert(y); val[y]^=tp; push_up(y);
			p[++tot]=(M){x,y,tp}; sum^=tp;
		}
		else if(opt==3) {
			u=read();
			x=p[u].x,y=p[u].y,tp=p[u].tp;
			makert(x); val[x]^=tp; push_up(x);
			makert(y); val[y]^=tp; push_up(y); sum^=tp;
		}
		else {
			x=read(); y=read();
			makert(x); access(y); splay(y); 
			if(sz[x]==sum) puts("YES");
			else puts("NO");
		}
	} 	
    return 0;
}

2.DZY Love Chinese II

Description:

给你一个图,每次给出k条边,问断掉是否可以使原图不连通

Hint:

\(n,m \le 2*10^5\)

Solution:

这题就比较神仙了,首先搞出一棵生成树

对于非树边rand一个权值,它所覆盖的树边都异或上这个权值

查询就用线性基看是否有k条边的子集权值异或为0

/**************************************************************
    Problem: 3569
    User: cloud9
    Language: C++
    Result: Accepted
    Time:2004 ms
    Memory:38404 kb
****************************************************************/
 
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=5e5+5;
const ll inf=1e18;
int n,m,k,q,cnt,fa[mxn],hd[mxn],dep[mxn];
ll pre,c[mxn],d[65];
 
inline int read() {
    char c=getchar(); int x=0,f=1;
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}
 
struct ed {
    int to,nxt;
}t[mxn<<1];
 
struct T {
    int u,v,typ; 
    ll val;
}e[mxn<<1];
 
int find(int x) {
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
 
inline void add(int u,int v) {
    t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}
 
void dfs(int u,int fa) {
    dep[u]=dep[fa]+1;
    for(int i=hd[u];i;i=t[i].nxt) {
        int v=t[i].to;
        if(v==fa) continue ;
        dfs(v,u); c[u]^=c[v];
    }
} 
 
int main()
{
    srand(time(0)); srand(rand());
    n=read(); m=read();
    for(int i=1;i<=n;++i) fa[i]=i;
    for(int i=1;i<=m;++i) {
        e[i].u=read(); e[i].v=read();
        if(find(e[i].u)==find(e[i].v)) {
            e[i].typ=1,e[i].val=1ll*rand()*rand()%inf+1;
            c[e[i].u]^=e[i].val; c[e[i].v]^=e[i].val;
        }
        else {
            fa[find(e[i].u)]=find(e[i].v);
            add(e[i].u,e[i].v); add(e[i].v,e[i].u);
        }
    }
    dfs(1,0);
    for(int i=1;i<=m;++i) 
        if(!e[i].typ) {
            if(dep[e[i].u]>dep[e[i].v]) e[i].val=c[e[i].u];
            else e[i].val=c[e[i].v];
        }
    q=read();
    while(q--) {
        k=read(); int res=0; int x;
        for(int i=63;i>=0;--i) d[i]=0; 
        while(k--) {
            x=read(); x^=pre; int val=e[x].val;
            for(int i=63;i>=0;--i) 
                if(val>>i&1) 
                    if(!d[i]) {
                        d[i]=val; 
                        break;
                    }
                    else val^=d[i];
            if(!val) res=1;     
        }   
        if(res) puts("Disconnected");
        else puts("Connected");
        pre+=!res;
    }
    return 0;
}

posted @ 2019-03-24 09:16  cloud_9  阅读(233)  评论(0编辑  收藏  举报