可持久化并查集

可持久化数组
可持久化数组是一种可以回退,访问之前版本的数组
是一些其他可持久化数据结构的基石
例如可持久化并查集)

与普通并查集不同的是 这里用到了 按秩合并
不了解可以百度一下

添加链接描述

#include <stdio.h>
const int N = 2e5 + 7;
int rootfa[N], rootdep[N], cnt, tot;
struct Node {
 int l, r, val;
} T[N*40*2];
int n;
void insert(int l, int r, int &now) {
 now = ++ cnt;
 if (l == r) {
  T[now].val = ++ tot;
  return;
 }
 int mid = l + r >> 1;
 insert(l, mid, T[now].l);
 insert(mid + 1, r, T[now].r);
}
void modify(int l, int r, int pre, int &now, int pos, int val) {
 T[now = ++cnt] = T[pre];
 if (l == r) {
  T[now].val = val;
  return;
 }
 int mid = l + r >> 1;
 if (pos <= mid) modify(l, mid, T[pre].l, T[now].l, pos, val);
 else modify(mid + 1, r, T[pre].r, T[now].r, pos, val);
}
int query(int l, int r, int now, int pos) {
 if (l == r) return T[now].val;
 int mid = l + r >> 1;
 if (pos <= mid) return query(l, mid , T[now].l, pos);
 else return query(mid + 1, r, T[now].r, pos);
}
int find(int ver, int x) {
 int fx = query(1, n, rootfa[ver], x);
 return fx == x ? x : find(ver, fx);
}
void merge(int ver, int x, int y) {
 x = find(ver - 1, x);   // ver  为一个新的版本还没有任何操作应该在上一个版本ver-1找
 y = find(ver - 1, y);
 if (x == y) {  // 在同一个集合 不需要操作直接继承上一个版本
  rootfa[ver] = rootfa[ver-1];
  rootdep[ver] = rootdep[ver-1];
 } else { //按秩合并   不了解可以百度一下
  int depx = query(1, n, rootdep[ver-1], x);
  int depy =  query(1, n, rootdep[ver-1], y);
  if (depx < depy) {
   modify(1, n, rootfa[ver-1], rootfa[ver], x, y);
   rootdep[ver] = rootdep[ver-1];
  } else if (depx > depy) {
   modify(1, n, rootfa[ver-1], rootfa[ver], y, x);
   rootdep[ver] = rootdep[ver-1];
  } else {
   modify(1, n, rootfa[ver-1], rootfa[ ver], y, x);
   modify(1, n, rootdep[ver-1], rootdep[ver], x, depx + 1);   // 此处应改dep数组
  }
 }
}
int main () {
 int m, opt, x, y;
 scanf ("%d%d", &n, &m);
 insert(1, n, rootfa[0]);
 for (int i = 1; i <= m; i ++ ) {
  scanf ("%d", &opt);
  switch(opt) {
   case 1: {
    scanf ("%d%d", &x, &y);
    merge(i, x, y);
    break;
   }
   case 2: {
    scanf ("%d", &x);
    rootfa[i] = rootfa[x];
    rootdep[i] = rootdep[x];
    break;
   }
   case 3: {
    scanf ("%d%d", &x, &y);
    rootfa[i] = rootfa[i-1];
    rootdep[i] = rootdep[i-1];
    int a = find(i,x);  // 找当前版本x的集合
    int b = find(i,y);  // 找当前版本y的集合
    printf ("%d\n", a == b ? 1 : 0);
    break;
   }
  }
 }
 return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值