左偏树,可并堆的一种,满足根节点优先级最小(最大),各结点优先级递增(递减)
定义左偏树的外界点为左子树或者右子树为空的结点。定义结点的距离为此结点到最近外界点的所经过的边数。
左偏树满足左偏性质,任意结点的左子结点的距离不小于右子结点的距离。
由左偏性质得:一结点的距离=0或(右子结点距离+1)
合并:将两子树中根较大(小)的树的根作为根节点,令其右子树与另外一棵树合并。
合并完成后比较左右两子结点的距离,确保左子结点距离大于等于右子结点距离。
插入:将新结点与原有树合并
删除:将根节点提出,合并其左右子树
合并代码如下:
int merge(int x,int y)
{
if(x==0)return y;
if(y==0)return x;
if(val[x]<val[y])swap(x,y);
ch[x][1]=merge(ch[x][1],y);
if(dis[ch[x][0]]<dis[ch[x][1]])swap(ch[x][0],ch[x][1]);
if(!ch[x][1]) dis[x]=0;
else dis[x]=dis[ch[x][1]]+1;
return x;
}
以下为猴王的代码:
题目:http://fzoj.xndxfz.com/JudgeOnline/problem.php?id=1636
#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAX=1e5+5;
int inline read()
{
int h,f=1;char ch;
while((ch=getchar())>'9'||ch<'0')
if(ch=='-')f=-1;h=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
h=h*10+ch-'0';return h*f;
}
int fa[MAX],ch[MAX][2],val[MAX],dis[MAX];
int merge(int x,int y)
{
if(x==0)return y;
if(y==0)return x;
if(val[x]<val[y])swap(x,y);
ch[x][1]=merge(ch[x][1],y);
if(dis[ch[x][0]]<dis[ch[x][1]])swap(ch[x][0],ch[x][1]);
if(!ch[x][1]) dis[x]=0;
else dis[x]=dis[ch[x][1]]+1;
return x;
}
int father(int n)
{
return (fa[n]==n)?n:fa[n]=father(fa[n]);
}
int fight(int x,int y)
{
int f1=father(x),f2=father(y);
val[f1]/=2,val[f2]/=2;
int root1=merge(ch[f1][1],ch[f1][0]),
root2=merge(ch[f2][1],ch[f2][0]),
root3=merge(root1,root2);
ch[f1][0]=ch[f2][0]=ch[f1][1]=ch[f2][1]=0;
int root4=merge(root3,f1),
root5=merge(root4,f2);
fa[root5]=fa[root4]=fa[root3]=fa[root2]=
fa[root1]=fa[f1]=fa[f2]=fa[x]=fa[y]=root5;
return val[root5];
}
int main()
{
int n=read();
for(int i=1;i<=n;i++)
fa[i]=i,val[i]=read();
int m=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
printf("%d\n",fight(x,y));
}
return 0;
}