可持久化平衡树 = 可持久化线段树 + 平衡线段树

可持久化平衡树

根据可持久化的基本思想可以得到: 一个数据结构可持久化, 可以存在一个儿子有多个父亲, 但是不允许一个父亲在同一位置 (如左儿子) 有多个儿子. 所以平衡树可持久化的基本条件是节点只记录儿子节点, 不记录父亲节点.

选择哪种平衡树用来持久化就是可持久化平衡树的第一步. 因为不能记录父亲, Treap 和 Splay 就已经被卡掉了. 然后查找一下我的知识储备, 还剩下替罪羊和 WBLT. 这两者都不记录父亲, 但是 WBLT 又名平衡线段树, 因为它的结构非常类似于线段树, 我们早已掌握了可持久化线段树, 那么可持久化平衡线段树树也变得简单多了.

因为儿子被多个父亲共用, 所以过程中要注意, 只能修改新建的节点的信息. 新建的节点指的是没有被共用, 只有一个父亲的节点.

代码逻辑还是比较清晰的, 唯一的不足是会有节点被浪费, 也就是这个节点不存在却需要为它开内存的情况, 所以空间最多的点 \(470MB\), 不过卡着过了.

钻了个空子, 用平衡线段树持久化了一下, 一般只要会可持久化线段树和平衡线段树的都会写.

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
#define Wild_Donkey 0
using namespace std;
inline unsigned RD() {
  unsigned intmp(0);
  char rdch(getchar());
  while (rdch < ‘0‘ || rdch > ‘9‘) rdch = getchar();
  while (rdch >= ‘0‘ && rdch <= ‘9‘) {
    intmp = (intmp << 3) + (intmp << 1) + rdch - ‘0‘;
    rdch = getchar();
  }
  return intmp;
}
inline int RDsg() {
  int rdtp(0), rdsg(1);
  char rdch(getchar());
  while ((rdch < ‘0‘ || rdch > ‘9‘) && (rdch != ‘-‘)) rdch = getchar();
  if (rdch == ‘-‘) {
    rdsg = -1;
    rdch = getchar();
  }
  while (rdch >= ‘0‘ && rdch <= ‘9‘) {
    rdtp = (rdtp << 3) + (rdtp << 1) + rdch - ‘0‘;
    rdch = getchar();
  }
  return rdtp * rdsg;
}
unsigned m, n, A, B, C, t, Ans(0);
int D;
struct Node {
  Node *LS, *RS;
  unsigned Cnt, Size;
  int Val, InVal;
}N[20000005], *Ver[500005], *CntN(N);
inline void Rotate(Node *x) {
  if(x->Size > 4) {
    register Node *Tmp(++CntN);
    if(x->LS->Size * 3 < x->RS->Size) {
      Tmp->LS = x->LS;
      Tmp->RS = x->RS->LS;
      x->RS = x->RS->RS;
      x->LS = Tmp;
      Tmp->InVal = Tmp->LS->InVal;
      Tmp->Val = Tmp->RS->Val;
      Tmp->Size = Tmp->LS->Size + Tmp->RS->Size;
      Tmp->Cnt = Tmp->LS->Cnt + Tmp->RS->Cnt;
      return;
    }
    if(x->RS->Size * 3 < x->LS->Size) {
      Tmp->RS = x->RS;
      Tmp->LS = x->LS->RS;
      x->LS = x->LS->LS;
      x->RS = Tmp;
      Tmp->InVal = Tmp->LS->InVal;
      Tmp->Val = Tmp->RS->Val; 
      Tmp->Size = Tmp->LS->Size + Tmp->RS->Size;
      Tmp->Cnt = Tmp->LS->Cnt + Tmp->RS->Cnt;
      return;
    }
  }
}
void Insert(Node *x, Node *y) {
  y->Cnt = x->Cnt + 1;
  if(x->Val == x->InVal) {
    if(x->Val ^ D) {
      y->Size = 2;
      y->LS = ++CntN, y->RS = ++CntN;
      if(x->Val < D) {
        y->LS->InVal = y->LS->Val = x->Val;
        y->RS->InVal = y->RS->Val = D;
        y->RS->Cnt = 1;
        y->LS->Cnt = x->Cnt;
        y->Val = D;
        y->InVal = x->InVal;
      } else {
        y->RS->InVal = y->RS->Val = x->Val;
        y->LS->InVal = y->LS->Val = D;
        y->LS->Cnt = 1;
        y->RS->Cnt = x->Cnt;
        y->InVal = D;
        y->Val = x->Val;
      }
      y->LS->Size = y->RS->Size = 1;
    } else {
      y->Val = y->InVal = D, y->Size = 1;
    }
    return;
  }
  if(D <= x->LS->Val) {
    y->RS = x->RS;
    Insert(x->LS, y->LS = ++CntN);
    y->InVal = y->LS->InVal;
    y->Val = x->Val;
  } else {
    y->LS = x->LS;
    Insert(x->RS, y->RS = ++CntN);
    y->Val = y->RS->Val;
    y->InVal = x->InVal;
  }
  y->Size = y->LS->Size + y->RS->Size;
  Rotate(y);
}
Node *Delete (Node *x, Node *y)  {
  if(x->Val == x->InVal) {
    y->Cnt = x->Cnt;
    if(x->Val == D) {
      --(y->Cnt);
    }
    if(y->Cnt) {
      y->Val = y->InVal = x->Val;
      y->Size = 1;
      return y;
    } else {
      return NULL;
    }
  }
  if(D <= x->LS->Val) {
    y->LS = Delete(x->LS, ++CntN);
    if(!(y->LS)) {
      return x->RS;
    }
    y->RS = x->RS;
    y->InVal = y->LS->InVal;
    y->Val = x->Val;
  } else {
    y->RS = Delete(x->RS, ++CntN);
    if(!(y->RS)) {
      return x->LS;
    }
    y->LS = x->LS;
    y->Val = y->RS->Val;
    y->InVal = x->InVal;
  }
  y->Size = y->LS->Size + y->RS->Size;
  y->Cnt = y->LS->Cnt + y->RS->Cnt;
  Rotate(y);
  return y;
}
void Find(Node *x) {
  if(x->Size == 1) {
    if(x->Val < D) {
      Ans += x->Cnt;
    }
    return;
  }
  if(D > x->LS->Val) {
    Ans += x->LS->Cnt;
    Find(x->RS);
  } else {
    Find(x->LS);
  }
  return;
}
void Rank(Node *x) {
  if(x->Size == 1) {
    Ans = x->Val;
    return;
  }
  if(x->LS->Cnt < C) {
    C -= x->LS->Cnt;
    return Rank(x->RS);
  } else {
    return Rank(x->LS);
  }
}
int main() {
  n = RD();
  Ver[0] = N;
  N->Val = N->InVal = 0x3f3f3f3f;
  N->Cnt = N->Size = 1;
  for (register unsigned i(1); i <= n; ++i) {
    A = RD(), B = RD();
    switch (B){
      case (1):{
        D = RDsg();
        Insert(Ver[A], Ver[i] = ++CntN);
        break;
      }
      case (2):{
        D = RDsg();
        Ver[i] = Delete(Ver[A], ++CntN);
        break;
      }
      case (3):{
        D = RDsg();
        Ans = 1, Find(Ver[i] = Ver[A]);
        break;
      }
      case (4):{
        C = RD();
        Rank(Ver[i] = Ver[A]);
        break;
      }
      case (5):{
        D = RDsg();
        Ans = 0, Find(Ver[i] = Ver[A]);
        C = Ans, Rank(Ver[i]);
        break;
      }
      case (6):{
        D = RDsg();
        ++C, Ans = 1, Find(Ver[i] = Ver[A]);
        C = Ans, Rank(Ver[i]);
        break;
      }
    }
    if(B >= 3) {
      printf("%d\n", Ans);
    }
  }
  return Wild_Donkey;
}

火车上的博客, 芜湖~

可持久化平衡树 = 可持久化线段树 + 平衡线段树

上一篇:数论函数


下一篇:AtCoder Beginner Contest 167