P3369 模板普通平衡树 (splay)

Posted lwqq3

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3369 模板普通平衡树 (splay)相关的知识,希望对你有一定的参考价值。

splay支持查询

1.第k大

2.第k大是谁

3.数的前驱

4.数的后继

5.添加删除

 

技术图片
#include <bits/stdc++.h>
using namespace std;

int rt, cnt;
int ch[100005][2];    //左右儿子
int fa[100005];       //父节点
int sz[100005];       //字树和
int cn[100005];       //当前点出现了多少次
int val[100005];      //当前点权值

void clear(int x) 
    sz[x] = fa[x] = ch[x][0] = ch[x][1] = cn[x] = val[x] = 0;


bool ws(int x)   //which son
    return ch[fa[x]][1] == x;  // 右儿子1 左儿子0


void update(int x) 
    if(x) 
        sz[x] = cn[x];
        if(ch[x][0]) sz[x] += sz[ch[x][0]];
        if(ch[x][1]) sz[x] += sz[ch[x][1]];
    


void setfa(int x, int f, int d) 
    if(x != 0) fa[x] = f;
    if(f != 0) ch[f][d] = x;


void rot(int x) 
    int f = fa[x]; int ff = fa[f]; int s1 = ws(x); int s2 = ws(f);
    int p = ch[x][s1 ^ 1];
    setfa(p, f, s1);
    setfa(f, x, s1 ^ 1);
    setfa(x, ff, s2);
    update(f);
    update(x);


void splay(int x) 
    for(; fa[x]; rot(x))
        if(fa[fa[x]] && ws(x) == ws(fa[x])) rot(fa[x]);
    rt = x;


void inser(int x) 
    if(rt == 0) 
        cnt++; ch[cnt][0] = ch[cnt][1] = fa[cnt] = 0;
        val[cnt] = x;
        cn[cnt] = 1;
        sz[cnt] = 1;
        rt = cnt;
        return;
    

    int now = rt, f = 0;
    while(1) 
        if(val[now] == x) 
            cn[now]++; update(now); update(f);
            splay(now);
            break;
        

        f = now;
        now = ch[now][val[now] < x];
        if(now == 0) 
            cnt++;
            val[cnt] = x;
            cn[cnt] = sz[cnt] = 1;
            fa[cnt] = f;
            ch[f][val[f] < x] = cnt;
            ch[cnt][1] = ch[cnt][0] = 0;
            update(f);
            splay(cnt);
            break;
        
    


int find(int x)      //查询 排名=有多少比他小的 + 1
    int now = rt, res = 0;
    while(1) 
        if(x < val[now]) now = ch[now][0]; //
        else 
            if(ch[now][0]) res += sz[ch[now][0]];
            if(x == val[now]) 
                splay(now);
                return res + 1;
            
            res += cn[now];
            now = ch[now][1];
        
    


int ffind(int x)   //查询排名为x的数
    int now = rt, res = 0;
    while(1) 
        if(ch[now][0] && x <= res + sz[ch[now][0]]) now = ch[now][0];
        else 
            if(ch[now][0]) res += sz[ch[now][0]];
            res += cn[now];

            if(res >= x) return val[now];
            now = ch[now][1];
        
    


int pre()   //前驱
    int now = ch[rt][0];
    while(ch[now][1]) now = ch[now][1];
    return now;


int nex() 
    int now = ch[rt][1];
    while(ch[now][0]) now = ch[now][0];
    return now;


void del(int x) 
    int no = find(x);
    if(cn[rt] > 1) 
        cn[rt]--;
        return;
    

    if(!ch[rt][0] && !ch[rt][1])   //没孩子
        clear(rt);
        rt = 0;
        return;
    
    if(!ch[rt][0]) 
        int oldrt = rt;
        rt = ch[rt][1]; fa[rt] = 0;
        clear(oldrt);
        return;
    

    if(!ch[rt][1]) 
        int oldrt = rt;
        rt = ch[rt][0]; fa[rt] = 0;
        clear(oldrt);
        return;
    
    // two children
    int lrt = pre();
    int oldrt = rt;
    splay(lrt);
    fa[ch[oldrt][1]] = lrt;
    ch[rt][1] = ch[oldrt][1];
    clear(oldrt);
    update(rt);


int main() 
    rt = 0;
    cnt = 0;
    int T;
    scanf("%d", &T);
    while(T--) 
        int opt, x;
        scanf("%d%d", &opt, &x);
        switch(opt) 
            case 1: inser(x); break;
            case 2: del(x); break;
            case 3: printf("%d\n", find(x)); break;
            case 4: printf("%d\n", ffind(x)); break;
            case 5: inser(x), printf("%d\n", val[pre()]), del(x); break;
            case 6: inser(x), printf("%d\n", val[nex()]), del(x); break;
        
    
    return 0;
View Code

 

以上是关于P3369 模板普通平衡树 (splay)的主要内容,如果未能解决你的问题,请参考以下文章

数组splay ------ luogu P3369 模板普通平衡树(Treap/SBT)

[P3369]普通平衡树(Splay版)

P3369 模板普通平衡树(Treap/SBT)

Luogu P3369 模板普通平衡树

题解 P3369 模板普通平衡树(Treap/SBT)

洛谷P3369普通平衡树(splay)