• Luogu P3835 【模板】可持久化平衡树(fhq Treap)


    P3835 【模板】可持久化平衡树

    题意

    题目背景

    本题为题目普通平衡树的可持久化加强版。

    题目描述

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

    1. 插入(x)
    2. 删除(x)数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
    3. 查询(x)数的排名(排名定义为比当前数小的数的个数(+1)。若有多个相同的数,因输出最小的排名)
    4. 查询排名为x的数
    5. (x)的前驱(前驱定义为小于(x),且最大的数,如不存在输出(-2147483647))
    6. (x)的后继(后继定义为大于(x),且最小的数,如不存在输出(2147483647))

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

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

    输入输出格式

    输入格式:

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

    接下来每行包含三个整数,第(i)行记为(v_i,opt_i,x_i)

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

    输出格式:

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

    输入输出样例

    输入样例#1:

    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
    

    输出样例#1:

    9
    1
    2
    10
    3
    

    说明

    数据范围:

    对于(28%)的数据满足:(1leq nleq 10)

    对于(44%)的数据满足:(1leq nleq 2cdot {10}^2)

    对于(60%)的数据满足:(1leq nleq 3cdot {10}^3)

    对于(84%)的数据满足:(1leq nleq {10}^5)

    对于(92%)的数据满足:(1leq nleq 2cdot {10}^5)

    对于(100%)的数据满足:(1leq nleq 5cdot {10}^5)

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

    样例说明:

    (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)天下第一! --Uranus

    在可持久化的状况下,(fhq Treap)的优越性被发挥得淋漓尽致。总体函数完全没有变化,只是多加了几条新建点的语句:

    int merge(int x,int y)
    {
        if(!x||!y) return x+y;
        if(rnd(x)>rnd(y))
        {
            int p=++cnt;node[p]=node[x];//new
            rs(p)=merge(rs(p),y);
            update(p);
            return p;
        }
        else
        {
            int p=++cnt;node[p]=node[y];//new
            ls(p)=merge(x,ls(p));
            update(p);
            return p;
        }
    }
    void split(int now,int k,int &x,int &y)
    {
        if(!now) x=y=0;
        else
        {
            if(val(now)<=k)
            {
                x=++cnt;node[x]=node[now];//new
                split(rs(x),k,rs(x),y);
                update(x);
            }
            else
            {
                y=++cnt;node[y]=node[now];//new
                split(ls(y),k,x,ls(y));
                update(y);
            }
        }
    }
    

    上面代码标了new的就是新语句。

    其他的操作完全相同,访问历史版本的操作也只需要对于每一个版本根不相同就可以了。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int INF=2147483647;
    const int MAXN=5e5+5;
    int n,cnt,rt[MAXN];
    struct fhq_Treap
    {
        int sz,rnd,val;
        int ls,rs;
        #define sz(a) node[a].sz
        #define rnd(a) node[a].rnd
        #define val(a) node[a].val
        #define ls(a) node[a].ls
        #define rs(a) node[a].rs
    }node[MAXN<<6];
    int read()
    {
        int re=0;bool f=true;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=false;ch=getchar();}
        while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
        return f?re:-re;
    }
    int newnode(int k)
    {
        sz(++cnt)=1;
        rnd(cnt)=rand();
        val(cnt)=k;
        return cnt;
    }
    void update(int p){sz(p)=sz(ls(p))+sz(rs(p))+1;}
    int merge(int x,int y)
    {
        if(!x||!y) return x+y;
        if(rnd(x)>rnd(y))
        {
            int p=++cnt;node[p]=node[x];
            rs(p)=merge(rs(p),y);
            update(p);
            return p;
        }
        else
        {
            int p=++cnt;node[p]=node[y];
            ls(p)=merge(x,ls(p));
            update(p);
            return p;
        }
    }
    void split(int now,int k,int &x,int &y)
    {
        if(!now) x=y=0;
        else
        {
            if(val(now)<=k)
            {
                x=++cnt;node[x]=node[now];
                split(rs(x),k,rs(x),y);
                update(x);
            }
            else
            {
                y=++cnt;node[y]=node[now];
                split(ls(y),k,x,ls(y));
                update(y);
            }
        }
    }
    int kth(int now,int k)
    {
        if(k==sz(ls(now))+1) return val(now);
        else if(k<=sz(ls(now))) return kth(ls(now),k);
        else return kth(rs(now),k-sz(ls(now))-1);
    }
    int main()
    {
        srand(time(0));
        n=read();
        for(int i=1;i<=n;i++)
        {
            int ver=read(),opt=read(),k=read();rt[i]=rt[ver];
            if(opt==1)
            {
                int x,y;
                split(rt[i],k,x,y);
                rt[i]=merge(merge(x,newnode(k)),y);
            }
            else if(opt==2)
            {
                int x,y,z;
                split(rt[i],k,x,z);
                split(x,k-1,x,y);
                y=merge(ls(y),rs(y));
                rt[i]=merge(merge(x,y),z);
            }
            else if(opt==3)
            {
                int x,y;
                split(rt[i],k-1,x,y);
                printf("%d
    ",sz(x)+1);
                rt[i]=merge(x,y);
            }
            else if(opt==4) printf("%d
    ",kth(rt[i],k));
            else if(opt==5)
            {
                int x,y;
                split(rt[i],k-1,x,y);
                if(!x) printf("%d
    ",-INF);
                else printf("%d
    ",kth(x,sz(x)));
                rt[i]=merge(x,y);
            }
            else if(opt==6)
            {
                int x,y;
                split(rt[i],k,x,y);
                if(!y) printf("%d
    ",INF);
                else printf("%d
    ",kth(y,1));
                rt[i]=merge(x,y);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    java笔试面试题目收集(一)
    java--用 * 打印出各种图形(新手请进)
    TextView属性大赏
    Meterial Or Ios ?
    android开发之后端云bmob的使用
    关于android开发自定义view
    第二周作业——面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?
    移动APP开发使用什么样的原型设计工具比较合适?
    测试
    转:nohup命令及其输出文件
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9887157.html
Copyright © 2020-2023  润新知