bzoj3673-可持久化并查集

Description

BZOJ

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]<<'
';
	return 0;
}
原文地址:https://www.cnblogs.com/ubospica/p/10645546.html