左偏树
左偏树
左偏树是一种可并堆,学来做 \(slope-trick\) 。
左偏树满足堆的性质,以及一个新的左偏性质。
先放定义:定义外部节点为没有左儿子或右儿子的节点。定义一个节点的距离(dis)为它到子树内最近的外部节点的距离,特别的,空节点的 \(dis\) 为 -1 。这是为了打代码方便,使得外部节点的 \(dis\) 可以初始化为 0。
根据这个定义,可以推出一棵以 \(x\) 为根的二叉树的大小至少为 \(2^{dis_x+1}-1\) ,同时也可以推出:对于一棵有 \(n\) 个节点的二叉树,其根节点的 \(dis\) 至多为 \(\left\lceil\log(n+1)\right\rceil\) 。
左偏性质即为对于每个点 \(x\) ,都有 \(dis_{ls}\ge dis_{rs}\) 。
合并
可并堆最重要的就是合并了!
对于两个小根堆的根 \(x,y\) ,假设 \(x<y\) ,不满足就交换。则 \(x\) 一定为当前子树的根。由于左偏,所以我们将 \(y\) 与 \(x\) 的右子树向下递归合并。回溯的时候要维护左偏性质,即判断路径上的每一个点 \(x\) 是否都有 \(dis_{ls}\ge dis_{rs}\) ,不满足就交换。时间复杂度为 \(O(\log n+\log m)\) ,其中 \(n,m\) 为合并的两个堆的大小。
其他操作
加入:直接当作合并来做
删除:若删除的点为根,则直接合并左右子树就好。若删除的点不为根,则需要额外维护每个点的父节点,并且在合并完儿子后,需要向上维护左偏性质。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
struct Date{
int ls,rs,dis,co,fa;long long x;
};Date d[N*2];
struct QUE{
int op,x,y;long long z;
};QUE que[N];
int ss,rt[N],tot,a[N];long long ans[N];
int heap_newnode(long long k)
{
tot++;d[tot].x=k;d[tot].co=tot;rt[tot]=tot;d[tot].dis=0;return tot;
}
int heap_find(int x)
{
if(d[x].co==x)
return x;
return d[x].co=heap_find(d[x].co);
}
int heap_merge(int x,int y)
{
if(x==0||y==0)
return x+y;
if(d[x].x>d[y].x)
swap(x,y);
d[x].rs=heap_merge(d[x].rs,y);
d[d[x].rs].fa=x;
if(d[d[x].ls].dis<d[d[x].rs].dis)
swap(d[x].ls,d[x].rs);
d[x].dis=d[d[x].rs].dis+1;
return x;
}
void heap_update(int x)
{
if(x==0)
return;
if(d[d[x].ls].dis<d[d[x].rs].dis)
swap(d[x].ls,d[x].rs);
heap_update(d[x].fa);
}
void heap_del(int x,int y)
{
x=heap_find(x);
if(rt[x]==y)
rt[x]=heap_merge(d[y].ls,d[y].rs);
else
{
x=heap_merge(d[y].ls,d[y].rs);
if(d[d[y].fa].ls==y)
d[d[y].fa].ls=x;
else
d[d[y].fa].rs=x;
d[x].fa=d[y].fa;
heap_update(x);
}
}
long long heap_min(int x)
{
x=heap_find(x);
return d[rt[x]].x;
}
void heap_Merge(int x,int y)
{
x=heap_find(x);y=heap_find(y);
d[y].co=x;
rt[x]=heap_merge(rt[x],rt[y]);
}
int main()
{
int n,m,i,x,y;
scanf("%d%d",&n,&m);
d[0].dis=-1;
for(i=1;i<=n;i++)
{
scanf("%d",&x);
a[i]=heap_newnode(x);
}
for(i=1;i<=m;i++)
{
scanf("%d",&que[i].op);
if(que[i].op==0)
scanf("%d%d",&que[i].x,&que[i].y);
if(que[i].op==1)
scanf("%d",&que[i].x);
if(que[i].op==2)
scanf("%d%d",&que[i].x,&que[i].y);
if(que[i].op==3)
scanf("%d%d%lld",&que[i].x,&que[i].y,&que[i].z);
}
for(i=1;i<=m;i++)
{
x=a[que[i].x];y=a[que[i].y];
if(que[i].op==0)
heap_del(x,y);
if(que[i].op==1)
ans[++ss]=heap_min(x);
if(que[i].op==2)
heap_Merge(x,y);
if(que[i].op==3)
{
heap_del(x,y);
heap_Merge(x,a[que[i].y]=heap_newnode(que[i].z));
}
}
for(i=1;i<=ss;i++)
printf("%lld\n",ans[i]);
return 0;
}

浙公网安备 33010602011771号