1. 基本操作

1.1. 重构

为了维持其平衡树的性质,设定参数 \(\alpha\) 决定是否重构。它的具体含义是若 \(\rm \max\{\text{siz}_{lson},\text{siz}_{rson}\}>\alpha\cdot \text{siz}_o\) 就重构 \(o\) 这棵子树。

重构具体就是将子树拍扁成一个序列,然后再重建。

1.2. 插入

插入节点可能会使平衡树不再平衡,我们从插入节点 \(u\)(叶子节点)向上遍历,选择一个子树最大的 \(u\) 的祖先进行重构。

1.3. 删除

对每个被删除的点暂时打一个懒标记,并从下至上去掉这个点的信息。一种延迟删除的方式是在每次删除后判断被删除的点是否已经达到 \(n/2\),如果达到就整棵树重构。

2. 时间复杂度

2.1. 插入

假设一个刚被重构的子树大小为 \(x\),最坏的情况显然是一直向它的某个子树插点。不妨设插入 \(d\) 次后需要再次重构这棵子树,那么有:

\[x/2+d>\alpha\cdot (x+d)\Rightarrow d>\frac{\alpha-1/2}{1-\alpha}\cdot x \]

因此至少每 \(\frac{\alpha-1/2}{1-\alpha}\cdot x\) 进行一次重构,而重构的复杂度是 \(\mathcal O(x+d)\),所以均摊重构复杂度为:

\[\frac{\mathcal O(x+\frac{\alpha-1/2}{1-\alpha}\cdot x)}{\frac{\alpha-1/2}{1-\alpha}\cdot x}=\mathcal O\left(\frac{1-\alpha}{\alpha-1/2}+1\right) \]

\(\alpha=0.75\) 时均摊为 \(\mathcal O(2)\). 所以插入操作就是朴素复杂度也即 \(\mathcal O(\log n)\),可以发现,\(\alpha\) 越大时均摊时间越小,但同时树也会变得不平衡。

2.2. 删除

\[\frac{\frac{n}{2}\cdot \mathcal O(\log n)+\mathcal O(n)}{\frac{n}{2}}=\mathcal O(\log n)+\mathcal O(2) \]

2.3. 其他常见平衡树操作

因为保证树高是 \(\log n\) 的,所以复杂度基本都能保证。

3. 代码实现

真它喵的调麻了,一直 \(\rm T\),一直 \(\rm T\),你它喵的一直 \(\rm T\)!结果最后发现是 Del() 中符号写反了,焯(t[rt].siz 不是删去的节点啊长点心吧)!

#include <cstdio>
#define print(x,y) write(x),putchar(y)

template <class T>
inline T read(const T sample) {
	T x=0; char s; bool f=0;
	while((s=getchar())>'9' or s<'0')
		f |= (s=='-');
	while(s>='0' and s<='9')
		x = (x<<1)+(x<<3)+(s^48),
		s = getchar();
	return f?-x:x;
}

template <class T>
inline void write(T x) {
    static int writ[40],w_tp=0;
    if(x<0) putchar('-'),x=-x;
    do writ[++w_tp]=(x-x/10*10),x/=10; while(x);
    while(putchar(writ[w_tp--]^48),w_tp);
}

#include <iostream>
using namespace std;

const bool ftcy = true;
const int maxn = 1e5+5;
const double alpha = 0.75;

int rt,seq[maxn],sq;
int rec[maxn],tp,idx,all;
struct node {
    bool ban;
    int fa,son[2],siz,v;
} t[maxn];

bool isbad(int o) {
    return alpha*t[o].siz<t[t[o].son[0]].siz ||
           alpha*t[o].siz<t[t[o].son[1]].siz;
}

int NewNode(int val,int f) {
    int id;
    if(tp) id = rec[tp --];
    else id = ++ idx;
    t[id].siz=1; t[id].ban=0;
    t[id].v=val, t[id].fa=f;
    return id;
}

void build(int &o,int l,int r) {
    if(l>r) return;
    int mid = l+r>>1; o=seq[mid];
    build(t[o].son[0],l,mid-1);
    build(t[o].son[1],mid+1,r);
    if(t[o].son[0]) t[t[o].son[0]].fa = o;
    if(t[o].son[1]) t[t[o].son[1]].fa = o;
    t[o].siz = t[t[o].son[0]].siz+t[t[o].son[1]].siz+1;
}

void pia(int o) {
    if(!o) return;
    pia(t[o].son[0]);
    if(!t[o].ban) seq[++ sq] = o;
    else rec[++ tp] = o, -- all;
    pia(t[o].son[1]);
    t[o].son[0]=t[o].son[1]=0;
}

void rebuild(int o) {
	// the original value of nw is important
    int f=t[o].fa,d=(t[f].son[1]==o),nw=0;
    sq=0; pia(o); 
	build(nw,1,sq); 
	if(f) t[f].son[d]=nw; 
	t[nw].fa = f;
    if(o==rt) rt=nw;
}

void Print(int o) {
	if(!o) return;
	printf("%d edge (%d, %d)\n",t[o].v,t[t[o].son[0]].v,t[t[o].son[1]].v);
	Print(t[o].son[0]);
	Print(t[o].son[1]);
}

void check(int x,int val) {
    int s = val<=t[x].v?0:1;
    while(t[x].son[s]) {
        if(isbad(t[x].son[s])) {
            rebuild(t[x].son[s]);
            return;
        }
        x = t[x].son[s], s = val<=t[x].v?0:1;
    }
}

void ins(int x) {
    ++ all;
    if(!rt) return rt=NewNode(x,0),void();
    int o=rt;
    while(ftcy) {
    	++ t[o].siz; // update the size!!!
        int f=o,d=(x>t[o].v); o=t[o].son[d];
        if(!o) {
            t[f].son[d]=NewNode(x,f);
            break;
        }
    }
    check(rt,x); 
}

void del(int rk) {
    int o=rt;
    while(ftcy) {
        -- t[o].siz; // update the size!!!
        if(!t[o].ban && t[t[o].son[0]].siz+1==rk) {
            t[o].ban = 1; return;
        }
        if(t[t[o].son[0]].siz+(t[o].ban^1)>=rk)
            o = t[o].son[0];
        else {
            rk -= t[t[o].son[0]].siz+(t[o].ban^1);
            o = t[o].son[1];
        }
    }
}

int rnk(int x) {
    int ret=0,o=rt;
    while(o) {
        if(x<=t[o].v) o=t[o].son[0];
        else ret+=t[t[o].son[0]].siz+(t[o].ban^1),o=t[o].son[1];
    }
    return ret+1;
}

// all: nodes on the tree
// t[rt].siz: nodes that truly exist

void Del(int x) {
    del(rnk(x));
    if(0.5*all>t[rt].siz)
        rebuild(rt);
}

int kth(int x) {
    int o=rt;
    while(ftcy) {
        if(x<=t[t[o].son[0]].siz)
            o=t[o].son[0];
        else {
            x -= t[t[o].son[0]].siz+(t[o].ban^1);
            if(!x) return t[o].v;
            o=t[o].son[1];
        }
    }
}

int main() {
    for(int n=read(9);n;--n) {
		int op = read(9), x = read(9);
		if(op==1) ins(x);
		else if(op==2) Del(x);
		else if(op==3) print(rnk(x),'\n');
		else if(op==4) print(kth(x),'\n');
		else if(op==5) print(kth(rnk(x)-1),'\n');
		else print(kth(rnk(x+1)),'\n');
	}
    return 0;
}
posted on 2020-03-16 08:56  Oxide  阅读(17)  评论(0编辑  收藏  举报