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

猜你喜欢

转载自www.cnblogs.com/lwqq3/p/11261567.html
今日推荐