【笔记】Treap 整理

版权声明:欢迎转载评论 https://blog.csdn.net/m0_37809890/article/details/82774698

前言

年轻时候写过一篇Treap原理,新写一篇的原因是想将它改造成类的形式并且添加lower_bound,upper_bound等实用函数。
BGM: Senbonzakura [SS-Extended+Bass]

接口

template <typename T>
class Treap
{
public:
	Treap(int n);
	void insert(T num);
	void del(T num);
	int lower_bound(T num); //返回大于等于x的第一个位置
	int upper_bound(T num); //返回大于x的第一个位置
	T at(int pos); //求第pos小的的值
	int size();
}

二分查找

lower_boundupper_bound这两个函数真的是非常经典了,基本可以适用于所有的查找情况,注意位置都是从1开始的。

  • upper_bound实现 lower_bound(x+1)
  • 求元素的出现次数 upper_bound(x)-lower_bound(x)
  • 求元素是否出现 upper_bound(x)!=lower_bound(x)
  • 求前驱(第一个小于给定值x的数) at(lower_bound(x)-1)
  • 求后继(第一个大于给定值x的数)at(upper_bound(x))
  • 查排名(比给定值小的个数+1)lower_bound(x)

实现

实现细节请看之前写的Treap原理

template <typename T>
class Treap
{
    vector<int> l,r,p,m,b; //左子树,右子树,随机权重,下辖数字个数,本值出现次数
    vector<T> v;
    int root,id,sz;
    void lturn(int &rt) //左旋
    {
        int nrt = r[rt];
        r[rt] = l[nrt];
        l[nrt] = rt;

        m[nrt] = m[rt];
        m[rt] = m[l[rt]] + m[r[rt]] + b[rt];
        rt = nrt;
    }
    void rturn(int &rt)
    {
        int nrt = l[rt];
        l[rt] = r[nrt];
        r[nrt] = rt;

        m[nrt] = m[rt];
        m[rt] = m[l[rt]] + m[r[rt]] + b[rt];
        rt = nrt;
    }
    void insert(int &rt , T num)
    {
        if(rt == 0)
        {
            id++;
            rt = id;
            v[rt] = num;
            m[rt] = b[rt] = 1;
            p[rt] = rand();
            return;
        }
        m[rt]++;
        if(num == v[rt])
            b[rt]++;
        else if(num > v[rt])
        {
            insert(r[rt], num);
            if(p[r[rt]] > p[rt]) lturn(rt);
        }
        else
        {
            insert(l[rt], num);
            if(p[l[rt]] > p[rt]) rturn(rt);
        }
    }
    void del(int &rt, T num)
    {
        if(rt == 0) return;
        if(v[rt] == num)
        {
            if(b[rt] > 1)
                b[rt]--, m[rt]--;
            else if(l[rt] * r[rt] == 0)
                rt = l[rt] + r[rt];
            else if(p[l[rt]] < p[r[rt]])
                lturn(rt), del(rt, num);
            else
                rturn(rt), del(rt, num);
        }
        else if(num > v[rt])
            m[rt]--, del(r[rt], num);
        else
            m[rt]--, del(l[rt], num);
    }
    int lower_bound(int rt, T num)
    {
        if(rt == 0) return 1;
        if(num == v[rt])
            return m[l[rt]] + 1;
        else if(num > v[rt])
            return m[l[rt]] + b[rt] + lower_bound(r[rt], num);
        return lower_bound(l[rt], num);
    }
    T at(int rt, int rank)
    {
        if(rt == 0) return 0;
        if(rank <= m[l[rt]])
            return at(l[rt], rank);
        rank -= m[l[rt]];
        if(rank <= b[rt])
            return v[rt];
        return at(r[rt], rank - b[rt]);
    }
public: 
    Treap(int n)
    {
        root = id = sz = 0;
        l = vector<int>(n+1);
        r = vector<int>(n+1);
        p = vector<int>(n+1);
        m = vector<int>(n+1);
        b = vector<int>(n+1);
        v = vector<T>(n+1);
    }
    inline void insert(T num){sz++;return insert(root, num);}
    inline void del(T num){sz--;return del(root, num);}
    inline int lower_bound(T num){return lower_bound(root, num);}
    inline int upper_bound(T num){return lower_bound(root, num+1);}
    inline T at(int pos){return at(root, pos);}
    inline int size(){return sz;}
};

模板题 Luogu P3369 普通平衡树

int main(void)
{
    int n = read();
    Treap<int> tr(n);
    while(n--)
    {
        int op = read(), num = read();
        if(op==1)
            tr.insert(num);
        else if(op==2)
            tr.del(num);
        else if(op==3)
            printf("%d\n",tr.lower_bound(num));
        else if(op==4)
            printf("%d\n",tr.at(num));
        else if(op==5)
            printf("%d\n",tr.at(tr.lower_bound(num)-1) );
        else
            printf("%d\n",tr.at(tr.upper_bound(num)) );
    }
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/82774698