[模板] 宗法树

详解极其优秀的数据结构:宗法树
其实我写得非常简陋
代码量小,类似平衡树+线段树的功能(除了LCT都能做),跑得飞快

网上没找到太多资料,先写一点

宗法树是这样的一棵二叉树:
数据存储在叶子里,非叶子存储两个子树的最大值/最小值,左小右大,每个非叶子节点必须有两个叶子

详解见注释

//Stay foolish,stay hungry,stay young,stay simple
#include<iostream>
#include<cstdio>
using namespace std;

const int MAXN=100005;
const int INF=1<<30;

//Patriarchal legal tree
#define leaf(x) (!(t[x].ch[0]||t[x].ch[1]))
struct Node{
    int val,size,ch[2];
}t[MAXN<<2]; 
int cnt,n,root;
/*如果空间紧张可以加垃圾回收*/ 
inline int newnode(int val){t[++cnt].val=val;t[cnt].size=1;return cnt;}
void pushup(int o){//维护非叶子节点的val(最大值)和size 
    if(leaf(o)) return;
    t[o].val = max(t[t[o].ch[0]].val,t[t[o].ch[1]].val);
    t[o].size = t[t[o].ch[0]].size+t[t[o].ch[1]].size;
}
void rotate(int o,int d){//可以看成一个"平行四边形"四顶点的平移 
    int r=t[o].ch[d];//备份 
    t[o].ch[d]=t[o].ch[d^1];//当前节点B侧->节点A侧节点 
    t[t[o].ch[d]].ch[d]=r;//当前节点A侧->当前节点A侧.A侧 
    t[t[o].ch[d]].ch[d^1]=t[t[o].ch[d]].ch[d];//当前节点A侧.A侧->当前节点A侧.B侧 
    t[o].ch[d^1]=t[t[o].ch[d]].ch[d^1];//当前节点A侧.B侧->当前节点B侧 
    pushup(t[o].ch[d]);pushup(t[o].ch[d^1]);
}
void maintain(int o){//维护非叶子节点
    if(leaf(o))return;
    if(t[t[o].ch[0]].size>=t[t[o].ch[1]].size<<2) rotate(o,0);
    if(t[t[o].ch[1]].size>=t[t[o].ch[0]].size<<2) rotate(o,1);
}
void insert(int &o,int val){
    if(!o){o=newnode(val);return;}//给新点开空间 
    if(leaf(o)){//到达叶子节点 
        t[o].ch[0]=newnode(min(val,t[o].val));//同时插入两个点! 
        t[o].ch[1]=newnode(max(val,t[o].val));//宗法树要求非叶子节点必须两个儿子 
        pushup(o);return;
    }
    val>t[t[o].ch[0]].val?insert(t[o].ch[1],val):insert(t[o].ch[0],val);//否则递归找点 
    pushup(o);
}
void del(int o,int fa,int val){
    if(leaf(o)){
        if(t[o].val==val)//找到该点 
            t[fa].ch[0]==o?t[fa]=t[t[fa].ch[1]]:t[fa]=t[t[fa].ch[0]];//用对立兄弟代替父亲实现删除       
        return;//此时兄弟仍为叶子,且满足宗法树定义 
    }
    val>t[t[o].ch[0]].val?del(t[o].ch[1],o,val):del(t[o].ch[0],o,val);//递归找点 
    pushup(o);
}
int rnk(int o,int val){
    if(leaf(o)) return val>t[o].val?2:1;
    return val>t[t[o].ch[0]].val?rnk(t[o].ch[1],val)+t[t[o].ch[0]].size:rnk(t[o].ch[0],val);
}
int kth(int o,int k){
    if(leaf(o)) return t[o].val;
    return k<=t[t[o].ch[0]].size?kth(t[o].ch[0],k):kth(t[o].ch[1],k-t[t[o].ch[0]].size);
}
int main()  {  
    scanf("%d",&n);  
    insert(root,INF);//记得加 
    for (int i=1;i<=n;i++){  
        int opt,x;  
        scanf("%d %d",&opt,&x);  
        if (opt==1) insert(root,x);  
        if (opt==2) del(root,0,x);  
        if (opt==3) printf("%d\n",rnk(root,x));  
        if (opt==4) printf("%d\n",kth(root,x));  
        if (opt==5) printf("%d\n",kth(root,rnk(root,x)-1));  
        if (opt==6) printf("%d\n",kth(root,rnk(root,x+1)));  
    }  
    return 0;
}  

附飞快的读入优化


struct file_io{
    #define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
    char inbuf[1 << 25], *pin, outbuf[1 << 25], *pout;
    int stk[20];

    file_io(): pout(outbuf) {fread(pin = inbuf, 1, 1 << 25, stdin);}
    ~file_io() {fwrite(outbuf, 1, pout - outbuf, stdout);}

    inline void getint(int &num){
        bool neg = 0; num = 0;
        while(!isdigit(*pin)) if(*pin++ == '-') neg = 1;
        while(isdigit(*pin)) num = num * 10 + *pin++ - '0';
        if(neg) num = -num;
    }

    inline void putint(int num){
        static int *v = stk;
        if(!num) *pout++ = '0';
        else{
            if(num < 0) *pout++ = '-', num = -num;
            for(; num; num /= 10) *v++ = num % 10;
            while(v != stk) *pout++ = *--v + '0';
        }
    }

    inline void nextline() {*pout++ = '\n';}
} fio;
#define getint(num) fio.getint(num)
#define putint(num) fio.putint(num)
#define nextline() fio.nextline()

猜你喜欢

转载自blog.csdn.net/gh0stcai/article/details/80153489