[关闭]
@ysner 2018-07-22T23:21:14.000000Z 字数 1625 阅读 1646

[SCOI2008]斜堆

贪心


题面

斜堆是一种二叉树,且每个非根结点的值都比它父亲大。
在斜堆中插入新元素的过程是递归进行的:

现给出一个大小为的斜堆,询问该斜堆字典序最小的插入序列。

解析

经过审题,我们发现每次插入元素后,该子树的根一定会有左子树,而右子树只能通过新元素经过、结点交换左右子树产生。
然后就看不出什么了?

一开始,我们不会求插入序列,但我们似乎可以求最后插入的那个元素。

于是我们可以初步确定它是极左链上的几个元素,但是并不确定他是哪一个。
对此可以讨论一下。设为符合条件的两点,深度大于

因而可证明最后插入的点一定是极左链上深度最小的点,或者是该点的是叶结点的左儿子。
而为了保证字典序最小,如果能取后者就取。

而找出最后插入的点并把它删掉后,问题就转化为规模更小的子问题,我们可以在剩下的斜堆中找出最后插入的点,以此类推。
最后倒着输出答案即可。
时间复杂度。。。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define re register
  8. #define il inline
  9. #define ll long long
  10. #define max(a,b) ((a)>(b)?(a):(b))
  11. #define min(a,b) ((a)<(b)?(a):(b))
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. int n,d[100],f[100],ls[100],rs[100],ans[100],top,flag,rt=1;
  16. il ll gi()
  17. {
  18. re ll x=0,t=1;
  19. re char ch=getchar();
  20. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  21. if(ch=='-') t=-1,ch=getchar();
  22. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  23. return x*t;
  24. }
  25. il void dfs(re int u)
  26. {
  27. if(!rs[u])
  28. {
  29. if(ls[u]&&!ls[ls[u]]&&!rs[ls[u]])
  30. {
  31. ans[++top]=ls[u],flag=1;
  32. ls[u]=0;f[ls[u]]=0;
  33. }
  34. else
  35. {
  36. ans[++top]=u,flag=1;
  37. if(u==rt) rt=ls[u];
  38. ls[f[u]]=ls[u];f[ls[u]]=f[u];f[u]=0;
  39. }
  40. }
  41. if(flag) return;
  42. if(ls[u]) dfs(ls[u]);
  43. if(flag) {swap(ls[u],rs[u]);return;}
  44. }
  45. int main()
  46. {
  47. n=gi();
  48. fp(i,2,n+1)
  49. {
  50. d[i]=gi();
  51. if(d[i]>=100) rs[d[i]-100+1]=i,f[i]=d[i]-100+1;
  52. else ls[d[i]+1]=i,f[i]=d[i]+1;
  53. }
  54. while(top<=n)
  55. {
  56. flag=0,dfs(rt);
  57. }
  58. fq(i,top,1) printf("%d ",ans[i]-1);puts("");
  59. return 0;
  60. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注