可持久化并查集
可持久化并查集
感觉就是把并查集的数组可持久化一下,本质上就是可持久化数组
由于要可持久化,路径压缩直接
考虑每次只访问
两个数组分别维护
并查集部分
询问
il int up(int x,int i){
ri int k;
while((k=fa.ask(fa.rot[i],x))^x) x=k;
return x;
}
合并
按 合并
il void merge(int a,int b,int i){
a=up(a,i),b=up(b,i);
if(a^b){
ri int sza=sz.ask(sz.rot[i],a);
ri int szb=sz.ask(sz.rot[i],b);
if(sza>szb) swap(sza,szb),swap(a,b);
fa.update(i,fa.rot[i],a,b);
sz.update(i,sz.rot[i],b,sza+szb);
}
return;
}
按树高合并
il void merge(int a,int b,int i){
a=up(a,i),b=up(b,i);
if(a^b){
ri int ha=hi.ask(hi.rot[i],a);
ri int hb=hi.ask(hi.rot[i],b);
if(ha<=hb){
fa.update(i,fa.rot[i],a,b);
if(ha==hb) hi.update(i,hi.rot[i],b,ha+1);
}
else fa.update(i,fa.rot[i],b,a);
}
return;
}
可持久化数组部分
struct arr{
int rot[N],cnt,a[N];
struct tre{
int ls,rs,val;
}t[N<<5];
il int build(int l,int r){
if(l>r) return 0;
ri int rt=++cnt,mid=(l+r)>>1;
t[rt].val=a[mid];
t[rt].ls=build(l,mid-1);
t[rt].rs=build(mid+1,r);
return rt;
}
il void update(int id,int pre,int pos,int k){
ri int l=1,r=n,rt=rot[id]=++cnt,mid;
while(pre){
t[rt]=t[pre],mid=(l+r)>>1;
if(mid==pos) {t[rt].val=k; break;}
if(pos<mid) r=mid-1,t[rt].ls=++cnt,pre=t[pre].ls,rt=t[rt].ls;
else l=mid+1,t[rt].rs=++cnt,pre=t[pre].rs,rt=t[rt].rs;
}
return;
}
il int ask(int rt,int pos){
ri int l=1,r=n,mid;
while(rt&&l<=r){
mid=(l+r)>>1;
if(mid==pos) return t[rt].val;
if(pos<mid) r=mid-1,rt=t[rt].ls;
else l=mid+1,rt=t[rt].rs;
}
return 0;
}
};
code(按 合并)
#include<bits/stdc++.h>
#define il inline
#define cs const
#define ri register
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10|48),void();
}
} using namespace Q;
cs int N=1e5+1;
int n,m;
struct arr{
int rot[N],cnt,a[N];
struct tre{
int ls,rs,val;
}t[N<<5];
il int build(int l,int r){
if(l>r) return 0;
ri int rt=++cnt,mid=(l+r)>>1;
t[rt].val=a[mid];
t[rt].ls=build(l,mid-1);
t[rt].rs=build(mid+1,r);
return rt;
}
il void update(int id,int pre,int pos,int k){
ri int l=1,r=n,rt=rot[id]=++cnt,mid;
while(pre){
t[rt]=t[pre],mid=(l+r)>>1;
if(mid==pos) {t[rt].val=k; break;}
if(pos<mid) r=mid-1,t[rt].ls=++cnt,pre=t[pre].ls,rt=t[rt].ls;
else l=mid+1,t[rt].rs=++cnt,pre=t[pre].rs,rt=t[rt].rs;
}
return;
}
il int ask(int rt,int pos){
ri int l=1,r=n,mid;
while(rt&&l<=r){
mid=(l+r)>>1;
if(mid==pos) return t[rt].val;
if(pos<mid) r=mid-1,rt=t[rt].ls;
else l=mid+1,rt=t[rt].rs;
}
return 0;
}
}fa,sz;
namespace Set{
il int up(int x,int i){
ri int k;
while((k=fa.ask(fa.rot[i],x))^x) x=k;
return x;
}
il void merge(int a,int b,int i){
a=up(a,i),b=up(b,i);
if(a^b){
ri int sza=sz.ask(sz.rot[i],a);
ri int szb=sz.ask(sz.rot[i],b);
if(sza>szb) swap(sza,szb),swap(a,b);
fa.update(i,fa.rot[i],a,b);
sz.update(i,sz.rot[i],b,sza+szb);
}
return;
}
} using namespace Set;
signed main(){
n=rd(),m=rd();
for(ri int i=1;i<=n;++i) fa.a[i]=i,sz.a[i]=1;
fa.rot[0]=fa.build(1,n),sz.rot[0]=sz.build(1,n);
for(ri int i=1,op,a,b;i<=m;++i){
op=rd(),fa.rot[i]=fa.rot[i-1],sz.rot[i]=sz.rot[i-1];
if(op==1) a=rd(),b=rd(),merge(a,b,i);
else if(op==2) a=rd(),fa.rot[i]=fa.rot[a],sz.rot[i]=sz.rot[a];
else a=rd(),b=rd(),putchar((up(a,i)==up(b,i))|48),putchar(10);
}
return 0;
}
code(按树高合并)
#include<bits/stdc++.h>
#define il inline
#define cs const
#define ri register
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10|48),void();
}
} using namespace Q;
cs int N=1e5+1;
int n,m;
struct arr{
int rot[N],cnt,a[N];
struct tre{
int ls,rs,val;
}t[N<<5];
il int build(int l,int r){
if(l>r) return 0;
ri int rt=++cnt,mid=(l+r)>>1;
t[rt].val=a[mid];
t[rt].ls=build(l,mid-1);
t[rt].rs=build(mid+1,r);
return rt;
}
il void update(int id,int pre,int pos,int k){
ri int l=1,r=n,rt=rot[id]=++cnt,mid;
while(pre){
t[rt]=t[pre],mid=(l+r)>>1;
if(mid==pos) {t[rt].val=k; break;}
if(pos<mid) r=mid-1,t[rt].ls=++cnt,pre=t[pre].ls,rt=t[rt].ls;
else l=mid+1,t[rt].rs=++cnt,pre=t[pre].rs,rt=t[rt].rs;
}
return;
}
il int ask(int rt,int pos){
ri int l=1,r=n,mid;
while(rt&&l<=r){
mid=(l+r)>>1;
if(mid==pos) return t[rt].val;
if(pos<mid) r=mid-1,rt=t[rt].ls;
else l=mid+1,rt=t[rt].rs;
}
return 0;
}
}fa,hi;
namespace Set{
il int up(int x,int i){
ri int k;
while((k=fa.ask(fa.rot[i],x))^x) x=k;
return x;
}
il void merge(int a,int b,int i){
a=up(a,i),b=up(b,i);
if(a^b){
ri int ha=hi.ask(hi.rot[i],a);
ri int hb=hi.ask(hi.rot[i],b);
if(ha<=hb){
fa.update(i,fa.rot[i],a,b);
if(ha==hb) hi.update(i,hi.rot[i],b,ha+1);
}
else fa.update(i,fa.rot[i],b,a);
}
return;
}
} using namespace Set;
signed main(){
n=rd(),m=rd();
for(ri int i=1;i<=n;++i) fa.a[i]=i,hi.a[i]=1;
fa.rot[0]=fa.build(1,n),hi.rot[0]=hi.build(1,n);
for(ri int i=1,op,a,b;i<=m;++i){
op=rd(),fa.rot[i]=fa.rot[i-1],hi.rot[i]=hi.rot[i-1];
if(op==1) a=rd(),b=rd(),merge(a,b,i);
else if(op==2) a=rd(),fa.rot[i]=fa.rot[a],hi.rot[i]=hi.rot[a];
else a=rd(),b=rd(),putchar((up(a,i)==up(b,i))|48),putchar(10);
}
return 0;
}
I went to the woods because I wanted to live deliberately, I wanted to live deep and suck out all the marrow of life, and not when I had come to die, discover that I had not live.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)