可持久化并查集小结

https://www.zybuluo.com/ysner/note/1253722

定义

允许恢复历史状态的并查集。

建立

建\(Q\)棵主席树,每个主席树上维护当前状态并查集各个节点的父亲。

(实际上就是并查集和主席树强行捆绑在一起)

操作

每次操作前自动继承上次操作后的状态。

  • 合并\(a,b\)所在集合

    把两棵主席树按秩合并(深度大的合并到深度小的)。

    如果两棵主席树合并时深度相等,给合并后的主席树深度\(+1\)(要不然哪来的秩)

  • 回到第\(k\)次操作之后的状态

    把当前主席树的根赋值为第\(k\)棵主席树的即可。

  • 询问\(a\),\(b\)是否属于同一集合

    并查集(主)+主席树(辅)查询两者祖先,比较是否相等。

    用途

  • \(bzoj\)上刷\(AC\)量
  • ???
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define re register
#define il inline
#define ls t[x][0]
#define rs t[x][1]
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=5e6+100;
int n,m,rt[N],tot,f[N],t[N][2],d[N];
il int gi()
{
  re int x=0,t=1;
  re char ch=getchar();
  while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
  if(ch==‘-‘) t=-1,ch=getchar();
  while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-48,ch=getchar();
  return x*t;
}
il void Build(re int &x,re int l,re int r)
{
  x=++tot;
  if(l==r) {f[x]=l;return;}
  re int mid=l+r>>1;
  Build(ls,l,mid);Build(rs,mid+1,r);
}
il void Modify(re int &x,re int las,re int l,re int r,re int pos,re int ff)
{
  x=++tot;
  if(l==r) {f[x]=ff;d[x]=d[las];return;}
  re int mid=l+r>>1;
  ls=t[las][0];rs=t[las][1];
  if(pos<=mid) Modify(ls,t[las][0],l,mid,pos,ff);
  else Modify(rs,t[las][1],mid+1,r,pos,ff);
}
il int Query(re int x,re int l,re int r,re int pos)
{
  if(l==r) return x;
  re int mid=l+r>>1;
  if(pos<=mid) return Query(ls,l,mid,pos);
  else return Query(rs,mid+1,r,pos);
}
il void add(re int x,re int l,re int r,re int pos)
{
  if(l==r) {++d[x];return;}
  re int mid=l+r>>1;
  if(pos<=mid) add(ls,l,mid,pos);
  else add(rs,mid+1,r,pos);
}
il int find(re int rt,re int x)
{
  re int fa=Query(rt,1,n,x);
  return x==f[fa]?fa:find(rt,f[fa]);
}
int main()
{
  n=gi();m=gi();
  Build(rt[0],1,n);
  fp(i,1,m)
    {
      re int op=gi();
      if(op==1)
    {
      rt[i]=rt[i-1];
      re int x=find(rt[i],gi()),y=find(rt[i],gi());
      if(f[x]==f[y]) continue;
      if(d[x]>d[y]) swap(x,y);
      Modify(rt[i],rt[i-1],1,n,f[x],f[y]);
      if(d[x]==d[y]) add(rt[i],1,n,f[y]);
    }
      if(op==2) rt[i]=rt[gi()];
      if(op==3)
    {
      rt[i]=rt[i-1];
      re int x=find(rt[i],gi()),y=find(rt[i],gi());
      puts(f[x]==f[y]?"1":"0");
    }
    }
  return 0;
}

原文地址:https://www.cnblogs.com/yanshannan/p/9495513.html

时间: 2024-10-03 16:50:17

可持久化并查集小结的相关文章

可持久化并查集加强版 BZOJ 3674

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 3225  Solved: 1192[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后--hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可

bzoj3674: 可持久化并查集

用可持久化线段树维护可持久化并查集. 调了一下午,改为按秩合并就过了... #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=200100; const int INF=1e9+10; int n,m; int fa[ma

【BZOJ3674】可持久化并查集加强版

可持久化并查集我觉得就是可持久化数组的一种应用.可持久化数组,顾名思义,就是有历史版本的数组,那么如果我们暴力修改储存的话,修改O(n)查询O(1),空间O(n*m),这样肯定不可行,那么我们发现主席树有这样的功能,他可以快速复制,修改O(log),查询O(log),空间(m*log),是一个可行的方案.然后我们可持久化f数组维护fa,每次按照深度启发式合并,不进行路径压缩,这样能保证时间复杂度位单次O(log^2),空间复杂度为O(2*n+m*log).我不知道为什么不路径压缩,路径压缩是完全

bzoj3674 可持久化并查集加强版

Description 自从zkysb出了可持久化并查集后--hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:-- n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为00<n,m<=2*10^5 Samp

[bzoj3673][可持久化并查集 by zky] (rope(可持久化数组)+并查集=可持久化并查集)

Description n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6 1 1 2 3 1 2 2 0 3 1 2 2 1 3 1 2 Sample Output 1 0 1 Solution 用rope实现可持久化数组,用rope的历史记录功能实现可持久化并查集,通过时间168ms

【BZOJ-3673&amp;3674】可持久化并查集 可持久化线段树 + 并查集

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status][Discuss] Description n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6

BZOJ 3673: 可持久化并查集 by zky

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2084  Solved: 941[Submit][Status][Discuss] Description n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6

BZOJ 3674: 可持久化并查集加强版

3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 2605  Solved: 977[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:…… n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状

3674: 可持久化并查集加强版

Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 3592  Solved: 1337[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:…… n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询