@ysner
2018-07-23T07:21:14.000000Z
字数 1625
阅读 1873
贪心
斜堆是一种二叉树,且每个非根结点的值都比它父亲大。
在斜堆中插入新元素的过程是递归进行的:
现给出一个大小为的斜堆,询问该斜堆字典序最小的插入序列。
经过审题,我们发现每次插入元素后,该子树的根一定会有左子树,而右子树只能通过新元素经过、结点交换左右子树产生。
然后就看不出什么了?
一开始,我们不会求插入序列,但我们似乎可以求最后插入的那个元素。
于是我们可以初步确定它是极左链上的几个元素,但是并不确定他是哪一个。
对此可以讨论一下。设为符合条件的两点,深度大于。
因而可证明最后插入的点一定是极左链上深度最小的点,或者是该点的是叶结点的左儿子。
而为了保证字典序最小,如果能取后者就取。
而找出最后插入的点并把它删掉后,问题就转化为规模更小的子问题,我们可以在剩下的斜堆中找出最后插入的点,以此类推。
最后倒着输出答案即可。
时间复杂度。。。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
int n,d[100],f[100],ls[100],rs[100],ans[100],top,flag,rt=1;
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void dfs(re int u)
{
if(!rs[u])
{
if(ls[u]&&!ls[ls[u]]&&!rs[ls[u]])
{
ans[++top]=ls[u],flag=1;
ls[u]=0;f[ls[u]]=0;
}
else
{
ans[++top]=u,flag=1;
if(u==rt) rt=ls[u];
ls[f[u]]=ls[u];f[ls[u]]=f[u];f[u]=0;
}
}
if(flag) return;
if(ls[u]) dfs(ls[u]);
if(flag) {swap(ls[u],rs[u]);return;}
}
int main()
{
n=gi();
fp(i,2,n+1)
{
d[i]=gi();
if(d[i]>=100) rs[d[i]-100+1]=i,f[i]=d[i]-100+1;
else ls[d[i]+1]=i,f[i]=d[i]+1;
}
while(top<=n)
{
flag=0,dfs(rt);
}
fq(i,top,1) printf("%d ",ans[i]-1);puts("");
return 0;
}