zoukankan      html  css  js  c++  java
  • [Luogu 3835]【模板】可持久化平衡树

    Description

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):

    1. 插入x数

    2. 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)

    3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)

    4. 查询排名为x的数

    5. 求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)

    6. 求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)

    和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)

    每个版本的编号即为操作的序号(版本0即为初始状态,空树)

    Input

    第一行包含一个正整数N,表示操作的总数。

    接下来每行包含三个正整数,第 $i$ 行记为 $v_i, opt_i, x_i$。

    $v_i$表示基于的过去版本号( $ 0 leq v_i < i$ ),$opt_i$ 表示操作的序号( $ 1 leq opt leq 6 $ ), $x_i$ 表示参与操作的数值

    Output

    每行包含一个正整数,依次为各个3,4,5,6操作所对应的答案

    Sample Input

    10
    0 1 9
    1 1 3
    1 1 10
    2 4 2
    3 3 9
    3 1 2
    6 4 1
    6 2 9
    8 6 3
    4 5 8

    Sample Output

    9
    1
    2
    10
    3

    Hint

    数据范围:

    对于10%的数据满足: $ 1 leq n leq 10 $

    对于30%的数据满足: $ 1 leq n leq 2cdot {10}^2 $

    对于50%的数据满足: $ 1 leq n leq 3cdot {10}^3 $

    对于80%的数据满足: $ 1 leq n leq {10}^5 $

    对于90%的数据满足: $ 1 leq n leq 2cdot {10}^5 $

    对于100%的数据满足: $ 1 leq n leq 5cdot {10}^5 $ , $-{10}^9 leq x_i leq {10}^9$

    经实测,正常常数的可持久化平衡树均可通过,请各位放心

    样例说明:

    共10次操作,11个版本,各版本的状况依次是:

    1. $[]$

    2. $[9]$

    3. $[3, 9]$

    4. $[9, 10]$

    5. $[3, 9]$

    6. $[9, 10]$

    7. $[2, 9, 10]$

    8. $[2, 9, 10]$

    9. $[2, 10]$

    10. $[2, 10]$

    11. $[3, 9]$

    题解

    用 $fhq\_treap$ 来实现可持久化。

    对于新建的版本,需要更新的点只有 $split$ 和 $merge$ 经过的点。

      1 //It is made by Awson on 2018.1.3
      2 #include <set>
      3 #include <map>
      4 #include <cmath>
      5 #include <ctime>
      6 #include <queue>
      7 #include <stack>
      8 #include <cstdio>
      9 #include <string>
     10 #include <vector>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define LL long long
     16 #define LD long double
     17 #define Max(a, b) ((a) > (b) ? (a) : (b))
     18 #define Min(a, b) ((a) < (b) ? (a) : (b))
     19 using namespace std;
     20 const int N = 5e5;
     21 const int M = N*50;
     22 const int INF = ~0u>>1;
     23 
     24 struct fhq_Treap {
     25     int root[N+5], ch[M+5][2], key[M+5], lev[M+5], size[M+5], tot;
     26     queue<int>mem;
     27     int newnode(int keyy) {
     28     int o;
     29     if (!mem.empty()) o = mem.front(), mem.pop();
     30       else o = ++tot;
     31     ch[o][0] = ch[o][1] = 0, key[o] = keyy, lev[o] = rand(), size[o] = 1;
     32     return o;
     33     }
     34     int cpynode(int r) {
     35     int o;
     36     if (!mem.empty()) o = mem.front(), mem.pop();
     37       else o = ++tot;
     38     ch[o][0] = ch[r][0], ch[o][1] = ch[r][1], key[o] = key[r], lev[o] = lev[r], size[o] = size[r];
     39     return o;
     40     }
     41     void pushup(int o) {
     42     size[o] = size[ch[o][0]]+size[ch[o][1]]+1;
     43     }
     44     void split(int o, int keyy, int &x, int &y) {
     45     if (!o) x = y = 0;
     46     else {
     47         if (key[o] <= keyy) {
     48         x = cpynode(o), split(ch[x][1], keyy, ch[x][1], y);
     49         pushup(x);
     50         }else {
     51         y = cpynode(o), split(ch[y][0], keyy, x, ch[y][0]);
     52         pushup(y);
     53         }
     54     }
     55     }
     56     int merge(int x, int y) {
     57     if (!x || !y) return x+y;
     58     if (lev[x] < lev[y]) {
     59         int r = cpynode(x);
     60         ch[r][1] = merge(ch[r][1], y);
     61         pushup(r); return r;
     62     }else {
     63         int r = cpynode(y);
     64         ch[r][0] = merge(x, ch[r][0]);
     65         pushup(r); return r;
     66     }
     67     }
     68     void insert(int &o, int keyy) {
     69     int r1, r2;
     70     split(o, keyy, r1, r2);
     71     o = merge(merge(r1, newnode(keyy)), r2);
     72     }
     73     void delet(int &o, int keyy) {
     74     int r1, r2, r3;
     75     split(o, keyy-1, r1, r2);
     76     split(r2, keyy, r2, r3);
     77     if (r2) mem.push(r2);
     78     r2 = merge(ch[r2][0], ch[r2][1]);
     79     o = merge(merge(r1, r2), r3);
     80     }
     81     int rank(int &o, int keyy) {
     82     int r1, r2;
     83     split(o, keyy-1, r1, r2);
     84     int ans = size[r1]+1;
     85     o = merge(r1, r2);
     86     return ans;
     87     }
     88     int get_num(int o, int rank) {
     89     if (rank == size[ch[o][0]]+1) return key[o];
     90     if (size[ch[o][0]] >= rank) return get_num(ch[o][0], rank);
     91     return get_num(ch[o][1], rank-(size[ch[o][0]]+1));
     92     }
     93     int get_pre(int &o, int keyy) {
     94     int r1, r2;
     95     split(o, keyy-1, r1, r2);
     96     int r = r1;
     97     while (ch[r][1]) r = ch[r][1];
     98     int ans = key[r];
     99     o = merge(r1, r2);
    100     return ans;
    101     }
    102     int get_nex(int &o, int keyy) {
    103     int r1, r2;
    104     split(o, keyy, r1, r2);
    105     int r = r2;
    106     while (ch[r][0]) r = ch[r][0];
    107     int ans = key[r];
    108     o = merge(r1, r2);
    109     return ans;
    110     }
    111 }T;
    112 int n, v, opt, x;
    113 
    114 void work() {
    115     srand(time(0));
    116     T.insert(T.root[0], -INF);
    117     T.insert(T.root[0], INF);
    118     scanf("%d", &n);
    119     for (int i = 1; i <= n; i++) {
    120     scanf("%d%d%d", &v, &opt, &x);
    121     T.root[i] = T.root[v];
    122     if (opt == 1) T.insert(T.root[i], x);
    123     else if (opt == 2) T.delet(T.root[i], x);
    124     else if (opt == 3) printf("%d
    ", T.rank(T.root[i], x)-1);
    125     else if (opt == 4) printf("%d
    ", T.get_num(T.root[i], x+1));
    126     else if (opt == 5) printf("%d
    ", T.get_pre(T.root[i], x));
    127     else printf("%d
    ", T.get_nex(T.root[i], x));
    128     }
    129 }
    130 int main() {
    131     work();
    132     return 0;
    133 }
  • 相关阅读:
    css3 rotate(1turn)的用法
    canvas svg webgl threejs d3js 的区别
    利用css3给座右铭设置漂亮的渐变色
    svg相关的知识
    Mark标记功能的实现(像手工标记的一样)
    终于搞清楚了正向代理与反向代理的区别
    获取免费ip_存入excel_用了线程池_封装清晰
    爬去京东——智能音箱
    滑动验证码
    天气爬取的笔记
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8182611.html
Copyright © 2011-2022 走看看