• 关于对treap的个人理解


    目的

    普通的二叉搜索树容易退化成一条链,使查询的复杂度从Ologn)变为O(n),所以使用随机数 数组辅助使其不易退化

    性质

    1val数组满足二叉搜索树的性质,即左子树内所有节点的val值小于根节点的val,右子树内的所有节点的val值大于根节点的val值(val数组内存的是题目中给出的要放进去的值);

    2key数组满足小(大)根堆的性质,即所有子树的key值小(大)于根节点的key值;

    作用

    查找前驱,后继;动态加点,删点;动态维护一个有序数集;

    操作:

    基本操作有

    右旋:(因为key值不满足小(大)根堆的特性)将这个节点的左儿子旋到这个节点的位置,

    设此节点为p,其左儿子为ls

    因为val[ls]<val[p](性质一)

    所以在将ls旋到p的位置这个过程中为了维护性质一,让p成为ls的右儿子,而ls原本的右儿子,设其为 x,因为val[x]<val[p](性质一)key[x]<key[p](性质二),而此时p的左儿子的为空(因为p的左儿子成了p的父亲节点)所以将x变成p的左儿子;

    左旋 :(因为key值不满足小(大)根堆的特性)将这个节点的右儿子旋到这个节点的位置(操作原理同上)

    模板 (前驱,后继,第k大值,某数的排名)

     https://loj.ac/problem/104

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    void FRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    void FCL(){fclose(stdin);fclose(stdout);}
    inline ll rd()
    {
        ll x=0,ert=1;char lk=getchar();
        while(!isdigit(lk)){if(lk=='-') ert=-1;lk=getchar();}
        while(isdigit(lk)){x=(x<<3)+(x<<1)+(lk-'0');lk=getchar();}
        return x*ert;
    }
    const int N=1e5+10,inf=1e9;
    int ls[N],rs[N],val[N],sz[N],cn[N],cnt,ra[N],rt;
    void up(int p){sz[p]=sz[ls[p]]+sz[rs[p]]+cn[p];}
    void ltu(int &p){int t=ls[p];ls[p]=rs[t];rs[t]=p;p=t;up(rs[p]);up(p);}
    void rtu(int &p){int t=rs[p];rs[p]=ls[t];ls[t]=p;p=t;up(ls[p]);up(p);}
    void ins(int &p,int x)
    {
        if(!p){p=++cnt;val[p]=x;sz[p]=1;cn[p]=1;ra[p]=rand();return ;}
        if(val[p]==x){cn[p]++;sz[p]++;return ;}
        if(x<val[p]) {ins(ls[p],x);if(ra[ls[p]]<ra[p]) ltu(p);up(p);}
        else {ins(rs[p],x);if(ra[rs[p]]<ra[p]) rtu(p);up(p);}
        return ;
    }
    void del(int &p,int x)
    {
        if(p==0) return ;
        if(val[p]==x)
        {
            if(cn[p]>1){cn[p]--;sz[p]--;return ;}
            else if(!ls[p]||!rs[p]) {p=ls[p]+rs[p];return ;}
            else if(ra[ls[p]]<ra[rs[p]]) ltu(p),del(p,x);
            else rtu(p),del(p,x);return ;
        }
        sz[p]--;
        x<val[p]?del(ls[p],x):del(rs[p],x);
    }
    int rak(int p,int x)
    {
        if(!p) return 0;
        if(val[p]==x) return sz[ls[p]]+1;
        return x<val[p]?rak(ls[p],x):rak(rs[p],x)+sz[ls[p]]+cn[p];
    }
    int num(int p,int x)
    {
        if(!p) return inf;
        if(x<=sz[ls[p]]) return num(ls[p],x);
        if((x-sz[ls[p]])<=cn[p]) return val[p];
        return num(rs[p],x-sz[ls[p]]-cn[p]); 
    }
    int pre(int p,int x)
    {
        if(!p) return -inf;
        return val[p]<x?max(val[p],pre(rs[p],x)):pre(ls[p],x);
    }
    int nxt(int p,int x)
    {
        if(!p) return inf;
        return val[p]>x?min(val[p],nxt(ls[p],x)):nxt(rs[p],x);
    }
    int main()
    {
        int n=rd();
        for(int i=1;i<=n;i++)
        {
            int opt=rd(),x=rd();
            switch(opt)
            {
                case 1:ins(rt,x);break;
                case 2:del(rt,x);break;
                case 3:printf("%d
    ",rak(rt,x));break;
                case 4:printf("%d
    ",num(rt,x));break;
                case 5:printf("%d
    ",pre(rt,x));break;
                case 6:printf("%d
    ",nxt(rt,x));break;
            }
        }
        return 0;
    }
  • 相关阅读:
    2331: [SCOI2011]地板 插头DP
    APIO2018 铜滚记
    2827: 千山鸟飞绝 非旋treap
    3682: Phorni 后缀平衡树 线段树
    4712: 洪水 基于链分治的动态DP
    20180507小测
    4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap
    5312: 冒险 线段树 复杂度分析
    5210: 最大连通子块和 动态DP 树链剖分
    4513: [Sdoi2016]储能表 数位DP
  • 原文地址:https://www.cnblogs.com/LWL--Figthing/p/9756238.html
Copyright © 2020-2023  润新知