详解极其优秀的数据结构:宗法树
其实我写得非常简陋
代码量小,类似平衡树+线段树的功能(除了LCT都能做),跑得飞快
网上没找到太多资料,先写一点
宗法树是这样的一棵二叉树:
数据存储在叶子里,非叶子存储两个子树的最大值/最小值,左小右大,每个非叶子节点必须有两个叶子
详解见注释
//Stay foolish,stay hungry,stay young,stay simple
#include
#include
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()