FHQ
FHQ 满足 \(val_{{ls}_{u}} \le val_u \le val_{{rs}_{u}}\)
对于每一个节点 \(u\) , 我们维护 \(sz_u\) 和 \(val_u\) 以及 \(rd_u\) (随机的 \(key\) ) .
- 按 \(val\) 分裂:
考虑维护两个指针,分别代表两课树,先判断 \(val_u\) 的大小与 \(v\) 的关系,然后向对应方向分裂。
具体地,如果 $val_u < v $ 那么把 \(u,ls_u\) 划入 \(x\) ,向\(rs_u\) 递归;相反,就向 \(ls_u\) 递归。
inline void spl(int u,int v,int &x,int &y){
if(!u) return x=y=0,void();
if(t[u].val<=v) spl(t[u].r,v,t[x=u].r,y);
else spl(t[u].l,v,x,t[y=u].l);
up(u);
}
2.按排名分裂:
类比按 \(val\) 分裂,对于 \(sz_{ls_u}\) 分讨即可。
3.合并
需要满足 \(\forall u \in x , v \in y 有 val_u \le val_v\)。
否则,我们只能进行启发式合并 \(O(log^2 n)\).
既然我们确定了 \(val\) 的关系,就只要考虑 \(key\) 的大小. 按照 \(key\) 的大小确定根节点,递归分讨即可。
inline int merge(int x,int y){
if(!x || !y) return x + y;
if(t[x].rd<t[y].rd) return t[y].l=merge(x,t[y].l),up(y),y;
return t[x].r=merge(t[x].r,y),up(x),x;
}
对于其他找 \(rank,pre,kth\) 等操作:直接在树上找或者利用分裂合并找答案。
一般地,在实现中,写 \(val < v\) 而不是 \(val \le v\).
知不可乎骤得,托遗响于悲风。
你不能只在进省队的时候才热爱 OI,你不能只在切出 DS 的时候才热爱 DS。

浙公网安备 33010602011771号