浅谈随机化异或解连通性问题
新套路学习了
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;
}