bzoj3673-可持久化并查集
Description
Solution
并不要求在线, 然后就有很优秀 好写 的离线做法...
我们考虑把每个操作建成一个点 \(i\).
对于 \(1\) 和 \(3\) 操作, 连边 \((i-1, i)\);
对于 \(2\) 操作, 连边 \((k_i, i)\).
容易发现这是一棵树, 并且并查集的操作可以回退, 那么我们直接在树上dfs, 在进入节点/回溯时处理merge/split/查询即可.
时间复杂度 \(O(m \log n)\)
代码超短...
Code
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;
//---------------------------------------
const int nsz=2e4+50;
int n,m,ans[nsz],las;
int fa[nsz],dep[nsz];
int stk[nsz][2],top=0;
void init(){rep(i,1,n)fa[i]=i,dep[i]=1;}
int find(int p){return p==fa[p]?p:find(fa[p]);}
int iscon(int a,int b){return find(a)==find(b);}
void merge(int a,int b){
a=find(a),b=find(b);
if(a==b)return;
if(dep[a]<dep[b])swap(a,b);
stk[++top][0]=b,stk[top][1]=dep[a];
fa[b]=a,dep[a]=max(dep[a],dep[b]+1);
}
void del(int top1){
for(;top!=top1;--top){
int a=stk[top][0],b=stk[top][1];
dep[fa[a]]=b,fa[a]=a;
}
}
struct tqu{int ty,a,b;}qu[nsz];
vector<int> ed[nsz];
void adde(int f,int t){ed[f].push_back(t);}
void dfs(int p){
int top1=top;
if(qu[p].ty==1)merge(qu[p].a,qu[p].b);
else if(qu[p].ty==3)ans[p]=iscon(qu[p].a,qu[p].b);
for(int v:ed[p]){
dfs(v);
}
del(top1);
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m;
init();
int a,b,c;
rep(i,1,m){
cin>>a>>b,qu[i].ty=a,qu[i].a=b;
if(a==2)adde(b,i);
else cin>>c,qu[i].b=c,adde(las,i);
las=i;
}
dfs(0);
rep(i,1,m)if(qu[i].ty==3)cout<<ans[i]<<'\n';
return 0;
}