博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据结构:可持久化并查集
阅读量:4671 次
发布时间:2019-06-09

本文共 2878 字,大约阅读时间需要 9 分钟。

在基础并查集上改良,让并查集支持回滚到历史版本

这里介绍一下普通并查集的两种优化,一个是路径压缩,一个是按秩合并(启发式合并)

路径压缩是在find上动手脚,让查询经过的点都直接与根相连,这样下次再查的时候复杂度就可以是O(1)

按秩合并是在union上动手脚,合并时让小集合拼接到较大集合上面,集合的大小用deep来衡量,这样就可以近似得到O(logn)的复杂度

在实现可持久化的时候,加上路径压缩会慢,只需要用按秩合并优化就好了

但是对于普通并查集来说,路径压缩就已经相当快了

其实并查集就是一个fa数组,那么可持久化并查集就是让这个数组更高级一些就可以了

多高级呢?支持单点修改和历史版本查询的数组

具体的做法是开一个可持久化线段树(可持久化线段树的思想在主席树里有介绍)

这棵线段树的非叶子节点i只负责维护lson和rson,不维护除此之外的任何信息

它的作用是方便我们在修改的时候快速地将[Li,Ri]这一段O(1)地指向它的历史版本

使用启发式合并

这样找一个节点所在集合的根,就需要查询log(n)次线段树

而每一次时间都是log(n),故时间为O(m*log^2(n)),空间为m*log(n)

1 #include
2 #include
3 using namespace std; 4 const int maxn=200005; 5 const int maxm=200005; 6 int n,m,sz,last; 7 int root[maxm],lch[10000005],rch[10000005],v[10000005],deep[10000005]; 8 inline int read() 9 {10 int x=0;char ch=getchar();11 while(ch>'9'||ch<'0') ch=getchar();12 while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}13 return x;14 }15 void build(int &k,int l,int r)16 {17 if(k==0) k=++sz;18 if(l==r) {v[k]=l;return;}19 int mid=(l+r)>>1;20 build(lch[k],l,mid);21 build(rch[k],mid+1,r);22 }23 void modify(int l,int r,int x,int &y,int pos,int val)24 {25 y=++sz;26 if(l==r) {v[y]=val;deep[y]=deep[x];return;}27 lch[y]=lch[x];rch[y]=rch[x];28 int mid=(l+r)>>1;29 if(pos<=mid)30 modify(l,mid,lch[x],lch[y],pos,val);31 else modify(mid+1,r,rch[x],rch[y],pos,val);32 }33 int query(int k,int l,int r,int pos)34 {35 if(l==r) return k;36 int mid=(l+r)>>1;37 if(pos<=mid) return query(lch[k],l,mid,pos);38 else return query(rch[k],mid+1,r,pos);39 }40 void add(int k,int l,int r,int pos)41 {42 if(l==r) {deep[k]++;return;}43 int mid=(l+r)>>1;44 if(pos<=mid) add(lch[k],l,mid,pos);45 else add(rch[k],mid+1,r,pos);46 }47 int find(int k,int x)48 {49 int p=query(k,1,n,x);50 if(x==v[p]) return p;51 return find(k,v[p]);52 }53 int main()54 {55 n=read();m=read();56 build(root[0],1,n);57 int f,k,a,b;58 for(int i=1;i<=m;i++)59 {60 f=read();61 if(f==1)62 {63 root[i]=root[i-1];64 a=read();b=read();a=a^last;b=b^last;65 int p=find(root[i],a),q=find(root[i],b);66 if(v[p]==v[q]) continue;67 if(deep[p]>deep[q]) swap(p,q);68 modify(1,n,root[i-1],root[i],v[p],v[q]);69 if(deep[p]==deep[q]) add(root[i],1,n,v[q]);70 }71 if(f==2)72 {73 k=read();k=k^last;root[i]=root[k];74 }75 if(f==3)76 {77 root[i]=root[i-1];78 a=read();b=read();a=a^last;b=b^last;79 int p=find(root[i],a),q=find(root[i],b);80 if(v[p]==v[q]) last=1;81 else last=0;82 printf("%d\n",last);83 }84 }85 }

仔细观察主席树和带修主席树的代码,可以发现有的地方是一致的

这里的add是改秩

转载于:https://www.cnblogs.com/aininot260/p/9518216.html

你可能感兴趣的文章
cookie之三天免登录代码
查看>>
1043 幸运号码 数位DP
查看>>
js18
查看>>
2018-2019-2 20175308实验一 《Java开发环境的熟悉》实验报告
查看>>
如何设置WIN7自动登录(去除登录密码)
查看>>
关于bash中if语法结构的广泛误解(转)
查看>>
10G整数文件中寻找中位数或者第K大数
查看>>
操作手机数据库的uri
查看>>
Python小应用1 - 抓取网页中的链接地址
查看>>
HTML表格和列表笔记&练习<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>关于表格的一些练...
查看>>
Hadoop HBase概念学习系列之hbase shell中执行java方法(高手必备)(二十五)
查看>>
数据类型
查看>>
SharePoint 2010中的内容类型集线器 - 内容类型发布与订阅
查看>>
如何解决在Windows Server 2008 R2 上安装证书服务重启后出现 CertificationAuthority 91错误事件...
查看>>
c# 获取键盘的输入
查看>>
mysql忘记密码
查看>>
小股神助A股股民畅享经济发展红利
查看>>
Python灰帽子pdf
查看>>
Node.js区块链开发pdf
查看>>
轻松学SQL Server数据库pdf
查看>>