平衡树小记

定义:\(u\) 的排名为中序遍历后 \(u\) 在第几个

求 rank,kth,pre,nxt 有统一写法

int kth(int rk){
	int u = head;
	while (u){
		if (siz[ls[u]]+1 == rk) return u;
		if (siz[ls[u]]+1 < rk){
			rk -= siz[ls[u]]+1;
			u = rs[u];
		} else {
			u = ls[u];
		}
	}
	return 0;
}
int rank(int x){
    int u = head, rk = 0;
    while (u){
        if (val[u] < x){
            rk += siz[ls[u]]+1;
            u = rs[u];
        } else {
            u = ls[u];
        }
    }
    return rk+1;
}
int pre(int x){
	int u = head, res = -INT_MAX;
	while (u){
		if (val[u] < x){
			res = max(res,val[u]);
			u = rs[u];
		} else {
			u = ls[u];
		}
	}
	return res;
}
int nxt(int x){
	int u = head, res = INT_MAX;
	while (u){
		if (val[u] > x){
			res = min(res,val[u]);
			u = ls[u];
		} else {
			u = rs[u];
		}
	}
	return res;
}

FHQ Treap

和 Treap 一样,每个节点随机一个优先级,且每个点的优先级都是其子树中最大的
核心操作:merge 和 split

  • merge 操作:合并两个平衡树,我们考虑按优先级合并,那么肯定是优先级大的作为当前的根,然后递归合并剩下的
int merge(int l,int r){
	if (!l) return r;
	if (!r) return l;
	if (pty[l] > pty[r]){
        // ls[l] 不变
		rs[l] = merge(rs[l],r);
		up(l);
		return l;
	} else {
        // rs[r] 不变
		ls[r] = merge(l,ls[r]);
		up(r);
		return r;
	}
}
  • split 操作:分裂出一个所有节点 键值/排名 \(\le x\) 的树,和一个所有节点 键值/排名 \(> x\) 的树
void split(int l,int r,int u,int num){
    // l:当前左树的节点,r:当前右树的节点,u:当前原树的节点
	if (!u){
		ls[r] = rs[l] = 0;
		return ;
	}
	if (val[u] <= num){
		rs[l] = u;
        //ls[l] 不用改,一定合法
		split(u,r,rs[u],num);
        //ls[u] 不用遍历,一定在左树
        
	} else {
		ls[r] = u;
		split(l,u,ls[u],num);
	}
	up(u);
}
posted @ 2025-11-07 19:50  huangyuze  阅读(1)  评论(0)    收藏  举报