洛谷P3369 平衡树Treap

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入 xx 数
  2. 删除 xx 数(若有多个相同的数,因只删除一个)
  3. 查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 )
  4. 查询排名为 xx 的数
  5. 求 xx 的前驱(前驱定义为小于 xx,且最大的数)
  6. 求 xx 的后继(后继定义为大于 xx,且最小的数)

输入格式

第一行为 nn,表示操作的个数,下面 nn 行每行有两个数 \text{opt}opt 和 xx,\text{opt}opt 表示操作的序号( 1 \leq \text{opt} \leq 61opt6 )

输出格式

对于操作 3,4,5,63,4,5,6 每行输出一个数,表示对应答案

输入输出样例

输入 #1
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
输出 #1
106465
84185
492737

说明/提示

【数据范围】
对于 100\%100% 的数据,1\le n \le 10^51n105,|x| \le 10^7x107

 

//https://www.luogu.com.cn/problem/P3369
#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+5;
const int inf=0x3f3f3f3f;

int sum ,R;
int size[maxn],v[maxn],num[maxn],rd[maxn],son[maxn][2];

void push_up(int p)
{
    size[p]=size[son[p][0]]+size[son[p][1]]+num[p];
}

void rotate(int &p,int d)
{
    int k=son[p][d^1];
    son[p][d^1]=son[k][d];
    son[k][d]=p;
    push_up(p);
    push_up(k);
    p=k;
}

void ins(int &p,int x)
{
    if (!p)
    {
        p=++sum;
        size[p]=num[p]=1;
        v[p]=x;
        rd[p]=rand();
        return;
    }
    if (v[p]==x)
    {
        num[p]++;
        size[p]++;
        return;
    }
    int d=(x>v[p]);
    ins(son[p][d],x);
    if (rd[p]<rd[son[p][d]]) rotate(p,d^1);
    push_up(p);
}

void del(int &p,int x)
{
    if (!p) return;
    if (x<v[p]) del(son[p][0],x);
    else if (x>v[p]) del(son[p][1],x);
    else
    {
        if (!son[p][0] && !son[p][1])
        {
            num[p]--; size[p]--; 
            if (num[p]==0) p=0;
        } 
        else if (son[p][0] && !son[p][1])
        {
            rotate(p,1);
            del(son[p][1],x);
        }
        else if (!son[p][0] && son[p][1])
        {
            rotate(p,0);
            del(son[p][0],x);
        }
        else if (son[p][0] && son[p][1])
        {
            int d=(rd[son[p][0]]>rd[son[p][1]]);
            rotate(p,d);
            del(son[p][d],x);
        }
    }
    push_up(p);
}

int rnk(int p,int x)
{
    if (!p) return 0;
    if (v[p]==x) return size[son[p][0]]+1;
    if (v[p]<x) return size[son[p][0]]+num[p]+rnk(son[p][1],x);
    if (v[p]>x) return rnk(son[p][0],x);
}

int find(int p,int x)
{
    if (!p) return 0;
    if (size[son[p][0]]>=x) return find(son[p][0],x);
    else if (size[son[p][0]]+num[p]<x)
        return find(son[p][1],x-num[p]-size[son[p][0]]);
    else return v[p];
}

int pre(int p,int x)
{
    if (!p) return -inf;
    if (v[p]>=x) return pre(son[p][0],x);
    else return max(v[p],pre(son[p][1],x));
}

int suc(int p,int x)
{
    if (!p) return inf;
    if (v[p]<=x) return suc(son[p][1],x);
    else return min(v[p],suc(son[p][0],x));
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int opt,x;
        scanf("%d%d",&opt,&x);
        if (opt==1) ins(R,x);
        else if (opt==2) del(R,x);
        else if (opt==3) printf("%d\n",rnk(R,x));
        else if (opt==4) printf("%d\n",find(R,x));
        else if (opt==5) printf("%d\n",pre(R,x));
        else if (opt==6) printf("%d\n",suc(R,x));
    }
    return 0;
}
View Code

 

posted @ 2020-06-10 10:38  N_Yokel  阅读(116)  评论(0编辑  收藏  举报