普通平衡树 - 替罪羊树

被学弟怼 : "你的博客上没有替罪羊树模板啊?"

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
    x=0;char ch;bool flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 100010;
const double alpha = 0.75;
struct Node{
    Node *ch[2];
    int key,siz,cnt;
    bool exist;
    void update(){
        siz = ch[0]->siz + ch[1]->siz + exist;
        cnt = ch[0]->cnt + ch[1]->cnt + 1;
    }
    bool pa(){
        return (ch[0]->cnt > cnt*alpha + 5) || (ch[1]->cnt > cnt*alpha + 5);
    }
};
struct STree{
    Node mem_poor[maxn];
    Node *tail,*root,*null;
    Node *bc[maxn];
    int bc_top;
    Node* NewNode(int key){
        Node *p = bc_top ? bc[--bc_top] : tail++;
        p->ch[0] = p->ch[1] = null;p->key = key;
        p->siz = p->cnt = 1;p->exist = true;
        return p;
    }
    void Travel(Node *p,vector<Node*>&v){
        if(p == null) return;
        Travel(p->ch[0],v);
        if(p->exist) v.push_back(p);
        else bc[bc_top++] = p;
        Travel(p->ch[1],v);
    }
    Node* Divide(vector<Node*>&v,int l,int r){
        if(l >= r) return null;
        int mid = l+r >> 1;
        Node *p = v[mid];
        p->ch[0] = Divide(v,l,mid);
        p->ch[1] = Divide(v,mid+1,r);
        p->update();return p;
    }
    void Rebuild(Node* &p){
        static vector<Node*>v;v.clear();
        Travel(p,v);p = Divide(v,0,v.size());
    }
    Node** Insert(Node* &p,int val){
        if(p == null){
            p = NewNode(val);
            return &null;
        }else{
            ++(p->siz);++(p->cnt);
            Node **res = Insert(p->ch[val >= p->key],val);
            if(p->pa()) res = &p;
            return res;
        }
    }
    void Erase(Node *p,int id){
        --(p->siz);
        int x = p->ch[0]->siz + p->exist;
        if(p->exist && id == x){
            p->exist = false;
            return;
        }else{
            if(id <= x) Erase(p->ch[0],id);
            else Erase(p->ch[1],id - x);
        }return;
    }
    void init(){
        tail = mem_poor;
        null = tail++;
        null->ch[0] = null->ch[1] = null;
        null->cnt = null->siz = null->key = 0;
        root = null;bc_top = 0;
    }
    STree(){init();}
    void Insert(int val){
        Node** p = Insert(root,val);
        if(*p != null) Rebuild(*p);
    }
    int Rank(int val){
        Node *nw = root;
        int ret = 1;
        while(nw != null){
            if(nw->key >= val) nw = nw->ch[0];
            else{
                ret += nw->ch[0]->siz + nw->exist;
                nw = nw->ch[1];
            }
        }return ret;
    }
    int Kth(int k){
        Node *nw = root;
        while(nw != null){
            if(nw->ch[0]->siz + 1 == k && nw->exist) return nw->key;
            else if(nw->ch[0]->siz >= k) nw = nw->ch[0];
            else k -= nw->ch[0]->siz + nw->exist,nw = nw->ch[1];
        }
    }
    void Erase(int k){
        Erase(root,Rank(k));
        if(root->siz < alpha*root->cnt) Rebuild(root);
    }
    void Erase_kth(int k){
        Erase(root,k);
        if(root->siz < alpha*root->cnt) Rebuild(root);
    }
}Sky;
int main(){
    int n;read(n);
    int k,m;
    while(n--){
        read(k);read(m);
        switch (k){
            case 1: Sky.Insert(m);break;
            case 2: Sky.Erase(m);break;
            case 3: printf("%d\n",Sky.Rank(m));break;
            case 4: printf("%d\n",Sky.Kth(m));break;
            case 5: printf("%d\n",Sky.Kth(Sky.Rank(m)-1));break;
            case 6: printf("%d\n",Sky.Kth(Sky.Rank(m+1)));break;
        }
    }
    getchar();getchar();
    return 0;
}

转载于:https://www.cnblogs.com/Skyminer/p/6973516.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值