P3369 【模板】普通平衡樹 —— Treap FHQtreap

Glowingfire發表於2024-11-29

【模板】普通平衡樹

題目描述

您需要動態地維護一個可重集合 \(M\),並且提供以下操作:

  1. \(M\) 中插入一個數 \(x\)
  2. \(M\) 中刪除一個數 \(x\)(若有多個相同的數,應只刪除一個)。
  3. 查詢 \(M\) 中有多少個數比 \(x\) 小,並且將得到的答案加一。
  4. 查詢如果將 \(M\) 從小到大排列後,排名位於第 \(x\) 位的數。
  5. 查詢 \(M\)\(x\) 的前驅(前驅定義為小於 \(x\),且最大的數)。
  6. 查詢 \(M\)\(x\) 的後繼(後繼定義為大於 \(x\),且最小的數)。

對於操作 3,5,6,不保證當前可重集中存在數 \(x\)

輸入格式

第一行為 \(n\),表示操作的個數,下面 \(n\) 行每行有兩個數 \(\text{opt}\)\(x\)\(\text{opt}\) 表示操作的序號($ 1 \leq \text{opt} \leq 6 $)

輸出格式

對於操作 \(3,4,5,6\) 每行輸出一個數,表示對應答案。

樣例 #1

樣例輸入 #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\%\) 的資料,\(1\le n \le 10^5\)\(|x| \le 10^7\)

來源:Tyvj1728 原名:普通平衡樹

在此鳴謝

分析

模板

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100,M=1e6+100;
struct node
{
    int lc,rc,pre,val,siz;
}t[N];
int tot,root,n;
void create(int x)
{
    ++tot;
    t[tot].lc=t[tot].rc=0;
    t[tot].val=x;
    t[tot].siz=1;
    t[tot].pre=rand();
}
void upd(int x)
{
    t[x].siz=t[t[x].lc].siz+t[t[x].rc].siz+1;
}
void split(int u,int x,int &L,int &R)
{
    if(u==0){L=R=0;return ;}
    if(t[u].val<=x)
    {
        L=u;
        split(t[u].rc,x,t[u].rc,R);
    }
    else
    {
        R=u;
        split(t[u].lc,x,L,t[u].lc);
    }
    upd(u);
}
int merg(int L,int R)
{
    if(L==0 || R==0)return L+R;
    if(t[L].pre>t[R].pre)
    {
        t[L].rc=merg(t[L].rc,R);
        upd(L);
        return L;
    }
    else
    {
        t[R].lc=merg(L,t[R].lc);
        upd(R);
        return R;
    }
}
void inser(int x)
{
    int L=0,R=0;
    create(x);
    split(root,x,L,R);
    L=merg(L,tot);
    root=merg(L,R);
}
void del(int x)
{
    int L=0,R=0,nw=0;
    split(root,x,L,R);
    split(L,x-1,L,nw);
    nw=merg(t[nw].lc,t[nw].rc);
    L=merg(L,nw);
    root=merg(L,R);
}
int finx(int x)
{
    int L=0,R=0,nw=0;
    split(root,x-1,L,R);
    nw=t[L].siz+1;
    root=merg(L,R);
    return nw;
}
int rk(int u,int k)
{
    if(t[t[u].lc].siz+1==k)return u;
    if(t[t[u].lc].siz>=k)return rk(t[u].lc,k);
    else return rk(t[u].rc,k-t[t[u].lc].siz-1);
}
int pre_x(int x)
{
    int L=0,R=0,nw=0;
    split(root,x-1,L,R);///L==0 -->RE
    nw=t[ rk(L,t[L].siz) ] .val;
    root=merg(L,R);
    return nw;
}

int suf_x(int x)
{
    int L=0,R=0,nw=0;
    split(root,x,L,R);
    nw=t[ rk(R,1) ] .val;
    root=merg(L,R);
    return nw;
}

void work()
{
    cin>>n;
    int opt,x;
    while(n--)
    {
        scanf("%d%d",&opt,&x);
        if(opt==1)inser(x);
        else if(opt==2)del(x);
        else
        {
            int ans=0;
            if(opt==3)ans=finx(x);
            else if(opt==4)ans=t[rk(root,x)].val;
            else if(opt==5)ans=pre_x(x);
            else ans=suf_x(x);
            printf("%d\n",ans);
        }
    }
}

int main()
{
    work();
    return 0;
}














相關文章