整理:可并堆

**# 关于左偏树的整理

1.左偏树是什么

左偏树是一种堆,支持 \(O(\log n)\) 地合并两个堆,插入一个新的元素,弹出堆顶元素,\(O(1)\) 查询堆顶元素。

左偏树满足一个性质,令 \(dist_u\) 表示以 \(u\) 为根的子树中,距离 \(u\) 最远的节点到 \(u\) 的距离,\(ls_u\)\(rs_u\) 表示 \(u\) 的左儿子和右儿子,那么就有 \(dist_{ls_u}\ge dist_{rs_u}\)

由于左偏树资瓷合并,所以左偏树又称可并堆。

2.左偏树的核心操作:merge

左偏树的 \(\operatorname{merge}\) 操作是左偏树的核心操作,左偏树的所有操作都是通过 \(\operatorname{merge}\) 操作实现的。

具体的,\(\operatorname{merge}\) 操作返回一个值,这里表示合并之后的堆顶元素编号,显然可以做一些特判,如果合并的两个堆有任意一个为空,那么返回另一个堆的堆顶编号即可,否则这里取对应值更小的编号作为合并之后的堆顶元素编号 \(u\)(如果为大根堆,就取对应值更大的编号作为合并之后的堆顶元素编号),目的是为了维护堆的性质,然后,我们合并 \(rs_u\) 代表的堆和另一个堆,递归下去,将返回的值作为 \(rs_u\),接着维护左偏性质,如果 \(dist_{rs_u}\)\(dist_{ls_u}\) 大,那么交换 \(rs_u\)\(ls_u\),将 \(dist_u\) 设为 \(dist_{ls_u}+1\)

int merge(int u,int v){
	if(u==0&&v==0)return 0;
    if(u==0)return v;
    if(v==0)return u;
    if(val[u]>val[v])swap(u,v);
    rs[u]=merge(rs[u],v);
    if(dist[rs[u]]>dist[ls[u]])swap(rs[u],ls[u]);
    dist[u]=dist[ls[u]]+1;
    return u;
}

3.左偏树的其他操作

1.在一个堆中加入新元素

我们将要加入的元素视为一个新堆,将原来的堆和新堆合并即可。

int insert(int u,int v){
    return merge(u,New(v));
}

2.删除一个堆的堆顶元素

直接合并 \(rs_u\)\(ls_u\) 对应的堆。

int pop(int u){
	return merge(ls[u],rs[u]);
}

3.将整个堆中的元素加上一个值

可以类比线段树做区间修改的时候打上的懒惰标记或者永久化标记。

对于懒惰标记,我们正常的打上标记,在访问儿子的时候下放即可。

void Tag(int p,int v){
	val[p]+=v;
    add[p]+=v;
    //add[p] 记录 p 对应的堆整体加了多少
}
void pushdown(int p){
	Tag(ls[p],add[p]);
    Tag(rs[p],add[p]);
    add[p]=0;
}
//更改之后的 merge 函数
int merge(int u,int v){
	if(u==0&&v==0)return 0;
    if(u==0)return v;
    if(v==0)return u;
    pushdown(u),pushdown(v);
    if(val[u]>val[v])swap(u,v);
    rs[u]=merge(rs[u],v);
    if(dist[rs[u]]>dist[ls[u]])swap(rs[u],ls[u]);
    dist[u]=dist[ls[u]]+1;
    return u;
}
//更改之后的 pop 函数
int pop(int u){
	pushdown(u);
    return merge(ls[u],rs[u]);
}

对于永久化标记,在合并时可能需要一些其他的操作。

我们记录一个 \(siz_u\) 表示 \(u\) 对应的这个堆的大小,在合并时,我们进行一个类似启发式合并的操作,将大小更大的那个堆的标记作为合并之后的堆的标记,然后将更小的那个堆的标记直接下放到堆中即可。

可以得到这样的总时间复杂度为 \(O(n\log n)\)

4.左偏树的使用

模版

左偏树常用于树上问题,这些题目的有一个一般模式,也就是对所有节点各自维护一个堆,在 dfs 过程中和儿子的堆合并,然后弹出不合法的点,修改其中的节点,计算对应的答案即可。

比如 城池攻占。**

posted @ 2025-04-08 18:41  陈牧九  阅读(31)  评论(0)    收藏  举报