可持久化Treap

可持久化fhq-Treap

treap很容易可持久化,只需要每次在进行需要产生新版本的操作的split时创建新的结点即可

一般来说仅有insert和delete产生新的版本,其他操作不影响树的中序序列(但具体依题目而定)

以luoguOJ P3835为例(即每种操作均产生新版本)写可持久化treap

#include<iostream>
#include<random>
#include<cstdio>
using namespace std;
typedef long long ll;

const int maxn = 5e5 + 50;

struct node{
  int l, r;
  int val, key;
  int size;
}fhq[maxn*50];
int cnt, root[maxn];

mt19937 rnd(233); //高质量随机数生成器

inline int newnode(int val){
  fhq[++cnt].val = val;
  fhq[cnt].key = rnd();
  fhq[cnt].size = 1;
  return cnt;
}

inline void print(int x){
  printf("%d\n", x);
}

inline void update(int now){
  fhq[now].size = fhq[fhq[now].l].size + fhq[fhq[now].r].size + 1;
}

void split(int now, int v, int &x, int &y){ //按值分裂树,小于等于v的分裂成一棵树,大于等于v的分裂成另一棵树
  if(!now) x = y = 0;
  else{
      if(fhq[now].val <= v){
          x = ++cnt;
          fhq[x] = fhq[now];
          split(fhq[x].r, v, fhq[x].r, y);
          update(x);
      }else{
          y = ++cnt;
          fhq[y] = fhq[now];
          split(fhq[y].l, v, x, fhq[y].l);
          update(y);
      }
  }
}

//传入时x为较小树,y为较大树
int merge(int x, int y){
  if(!x || !y) return x+y;
  if(fhq[x].key > fhq[y].key){
      fhq[x].r = merge(fhq[x].r, y);
      update(x);
      return x;
  }else{
      fhq[y].l = merge(x, fhq[y].l);
      update(y);
      return y;
  }
}

int x, y, z;
inline void ins(int val, int &root){
  split(root, val, x, y);
  root = merge(merge(x, newnode(val)), y);
}

inline void del(int val, int &root){
  split(root, val, x, z);
  split(x, val-1, x, y);
  y = merge(fhq[y].l, fhq[y].r);
  root = merge(merge(x, y), z);
}

inline void getrank(int val, int root){
  split(root, val-1, x, y);
  print(fhq[x].size+1);
  root = merge(x, y);
}

inline void getnum(int rank, int root){
  int now = root;
   
  while(now){
      if(fhq[fhq[now].l].size + 1 == rank) break;
      else if(fhq[fhq[now].l].size + 1 > rank) now = fhq[now].l;
      else{
          rank -= fhq[fhq[now].l].size + 1;
          now = fhq[now].r;
      }
  }
  print(fhq[now].val);
}

inline void pre(int val, int root){
  split(root, val-1, x, y);
  int now = x;
  while(fhq[now].r) now = fhq[now].r;
  print(fhq[now].val);
  root = merge(x, y);
}

inline void nxt(int val, int root){
  split(root, val, x, y);
  int now = y;
  while(fhq[now].l) now = fhq[now].l;
  print(fhq[now].val);
  root = merge(x, y);
}

int main(){
  //node a;
  int n;
  scanf("%d", &n);
  //newnode(531821);

  for(int i = 1; i <= n; i++){
      int op, x, v;
      scanf("%d%d%d", &v, &op, &x);
      root[i] = root[v];
      switch(op){
          case 1: ins(x, root[i]);
          break;
          case 2: del(x, root[i]);
          break;
          case 3: getrank(x, root[i]);
          break;
          case 4: getnum(x, root[i]);
          break;
          case 5: pre(x, root[i]);
          break;
          case 6: nxt(x, root[i]);
          break;
      }
      //cout<<"**"<<cnt<<"**\n";
  }
  return 0;
}

 

通过建立根结点的副本和分裂连接处的结点副本实现可持久化

split时需要newnode新结点来保存新版本树的连接处(其他的部分由不同版本treap公用)

每次复制旧版本号根结点后在其基础上进行从操作即可产生新版本的treap

posted @ 2020-11-23 21:05  IrIrIrllleaf  阅读(139)  评论(0编辑  收藏  举报