@ysner
2018-07-22T23:21:14.000000Z
字数 1625
阅读 2457
贪心
斜堆是一种二叉树,且每个非根结点的值都比它父亲大。
在斜堆中插入新元素的过程是递归进行的:
现给出一个大小为的斜堆,询问该斜堆字典序最小的插入序列。
经过审题,我们发现每次插入元素后,该子树的根一定会有左子树,而右子树只能通过新元素经过、结点交换左右子树产生。
然后就看不出什么了?
一开始,我们不会求插入序列,但我们似乎可以求最后插入的那个元素。
于是我们可以初步确定它是极左链上的几个元素,但是并不确定他是哪一个。
对此可以讨论一下。设为符合条件的两点,深度大于。
因而可证明最后插入的点一定是极左链上深度最小的点,或者是该点的是叶结点的左儿子。
而为了保证字典序最小,如果能取后者就取。
而找出最后插入的点并把它删掉后,问题就转化为规模更小的子问题,我们可以在剩下的斜堆中找出最后插入的点,以此类推。
最后倒着输出答案即可。
时间复杂度。。。
#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;}
