zoukankan      html  css  js  c++  java
  • 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
    ", find(x)); break;
                case 4: printf("%d
    ", ffind(x)); break;
                case 5: inser(x), printf("%d
    ", val[pre()]), del(x); break;
                case 6: inser(x), printf("%d
    ", val[nex()]), del(x); break;
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    整理了一份FAQ,新手看一下
    分享:pythonbitstring 3.1.2 发布
    分享:TokuDB v7 发布,并宣布全面开源
    在美国学CS能挣多少钱?美国IT公司标准 offer package详细数字及绿卡政策 | 美国留学申请与就业找工作咨询博客|Warald|一亩三分地论坛
    写的split带改进
    分享:一个多进程并发执行程序ps命令 ls命令
    分享:vi/vim使用进阶: 指随意动,移动如飞 (一)
    waning rm i rm rvfi
    分享:C++中头文件、源文件之间的区别与联系
    分享:神奇的动归状态转移方程——最优子序列
  • 原文地址:https://www.cnblogs.com/lwqq3/p/11261567.html
Copyright © 2011-2022 走看看