P3369 【模板】普通平衡樹(treap)

Self-Discipline發表於2018-09-05

題目:點選開啟連結

題意:中文題,不解釋。

分析:這題是平衡樹操作的裸題,用treap或者splay都行,我這裡用的是treap。treap入門推薦https://www.cnblogs.com/MyStringIsNotNull/p/9165675.html,寫的非常詳細,程式碼參考https://www.cnblogs.com/candy99/p/6105347.html

程式碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<unordered_map>
#include<unordered_set>
#include<algorithm>
#include<iostream>
#include<fstream>
#include<complex>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iomanip>
#include<string>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cctype>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
using namespace std;
#define pt(a) cout<<a<<endl
#define debug test
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
#define eps 1e-10
#define PI acos(-1.0)
typedef pair<int,int> PII;
const ll mod = 1e9+7;
const int N = 1e6+10;

ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qp(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
int to[4][2]={{-1,0},{1,0},{0,-1},{0,1}};

struct node{
    int l,r,size,v,w,rnd;///左、右子樹、包含本節點的子樹大小、節點的值、節點值的數量、優先順序
}t[N];
int cnt,root;///節點個數、根
inline void update(int x){t[x].size=t[t[x].l].size+t[t[x].r].size+t[x].w;}///更新節點的子樹個數
inline void rturn(int &x){///左旋
    int c=t[x].l;t[x].l=t[c].r;t[c].r=x;
    t[c].size=t[x].size;update(x);x=c;
}
inline void lturn(int &x){///右旋
    int c=t[x].r;t[x].r=t[c].l;t[c].l=x;
    t[c].size=t[x].size;update(x);x=c;
}
void insert(int &x,int v){///插入
    if(x==0){///空樹
        cnt++;x=cnt;
        t[cnt].l=t[cnt].r=0;
        t[cnt].v=v;t[cnt].w=t[cnt].size=1;t[cnt].rnd=rand();
        return;
    }
    t[x].size++;///子樹節點個數+1
    if(t[x].v==v) t[x].w++;///節點值次數+1
    else if(v<t[x].v){
        insert(t[x].l,v);/// 遞迴左子樹
        if(t[t[x].l].rnd<t[x].rnd) rturn(x);///插入後作出調整(右旋)
    }else{
        insert(t[x].r,v);/// 遞迴右子樹
        if(t[t[x].r].rnd<t[x].rnd) lturn(x);///插入後作出調整(左旋)
    }
}
void del(int &x,int v){///刪除值為x的數(若有多個相同的數,因只刪除一個)
    if(x==0) return;///空樹 直接返回
    if(t[x].v==v){
        if(t[x].w>1){t[x].w--;t[x].size--;return;}///次數>1 次數-1 返回
        if(t[x].l*t[x].r==0) x=t[x].l+t[x].r;///一個孩子為空,直接用另一個代替
        else if(t[t[x].l].rnd<t[t[x].r].rnd)
            rturn(x),del(x,v); ///右旋再繼續找
        else lturn(x),del(x,v);///左旋再繼續找
    }else {
        t[x].size--;///節點值次數-1
        if(v<t[x].v) del(t[x].l,v);///找左子樹
        else del(t[x].r,v);///找右子樹
    }
}
int rnk(int x,int v){///查詢數v的排名
    if(x==0) return 0;///空樹 返回0
    if(t[x].v==v) return t[t[x].l].size+1;///找到 返回
    else if(v<t[x].v) return rnk(t[x].l,v);///繼續找左子樹
    else return t[t[x].l].size+t[x].w+rnk(t[x].r,v);///+左子樹節點個數後 繼續找左子樹
}
int kth(int x,int k){///查詢排名為k的數
    if(x==0) return 0;///空樹 返回0
    if(k<=t[t[x].l].size) return kth(t[x].l,k);///左子樹節點個數大於k 繼續往左子樹找
    else if(k>t[t[x].l].size+t[x].w)
        return kth(t[x].r,k-t[t[x].l].size-t[x].w);///左子樹節點個數小於k 繼續往右子樹找
    else return t[x].v;///找到 返回
}
int ans;
void pre(int x,int v){///查詢v的前驅
    if(x==0) return;
    if(v>t[x].v) ans=x,pre(t[x].r,v);///找到小於v的節點 往右子樹找
    else pre(t[x].l,v);///否則往左子樹找
}
void suf(int x,int v){///查詢v的後繼
    if(x==0) return;
    if(v<t[x].v) ans=x,suf(t[x].l,v);///找到大於v的節點 往左子樹找
    else suf(t[x].r,v);///否則往右子樹找
}
int n,op,x;
int main(){
    srand(222);///隨機數種子
    cin>>n;
    while(n--){
        cin>>op>>x;
        if(op==1) insert(root,x);
        else if(op==2) del(root,x);
        else if(op==3) cout<<rnk(root,x)<<endl;
        else if(op==4) cout<<kth(root,x)<<endl;
        else if(op==5) ans=0,pre(root,x),cout<<t[ans].v<<endl;
        else if(op==6) ans=0,suf(root,x),cout<<t[ans].v<<endl;
    }
    return 0;
}

 

相關文章