[关闭]
@xiaoziyao 2020-05-19T23:13:53.000000Z 字数 2689 阅读 1033

CF38G Queue解题报告

解题报告


CF38G Queue解题报告:

题意:给定个点,每个点有一个权值与一个约束值,我们需要按顺序插入这个数,每次插入一个点后,如果这个点的权值比上一个点的权值大,则需要与上一个点交换位置,一个点最多能与个点交换位置,求最后的序列。

刚看到这道题,想维护小于一个值的一个数组,但是没搞出来,于是写了个Splay。

这道题所使用的Splay是类似【模板】文艺平衡树的Splay,叫做区间Splay,它就是以一个点的位置为权值来维护Splay的方法。

我们先定义一个数组,代表以为根节点的子树中最大值存在的位置,可以很容易写出它的方式:

  1. maxx[now]=val[now];
  2. if(a[maxx[chd[now][0]]]>a[maxx[now]])
  3. maxx[now]=maxx[chd[now][0]];
  4. if(a[maxx[chd[now][1]]]>a[maxx[now]])
  5. maxx[now]=maxx[chd[now][1]];

然后我们再考虑一个点的插入,当位置为,权值为的结点插入到位置后,可以发现如果大于位置的权值和的右子树的的权值的话,这个结点就可以插入到的左子树,否则就可以插入到右子树。

接下来,我们开始实现解决问题的核心操作函数(代表位置,代表约束值),我们可以分两种情况讨论一下:
1. 如果当前位置可以和前面的任意多个节点换(只要满足条件),那我们就可以直接从根插入这个节点。
2. 否则,你需要用循环(或递归)找出编号的节点,并将其设为根,因为这是一颗区间Splay,所以当前节点可以和这个的右子树中任意一个节点交换(只要满足条件),就可以从根的右儿子节点插入。

  1. void work(int p,int c){
  2. if(p-c>1){
  3. splay(getnum(p-c-1),0);
  4. insert(chd[root][1],root,p);
  5. }
  6. else insert(root,0,p);
  7. splay(cnt,0);
  8. }

最后输出用中序遍历,应该大家都会吧。

时间复杂度:次操作,每次操作用区间Splay可以达到的复杂度(可以用势能分析))

代码:

  1. #include<stdio.h>
  2. #define inf 1000000000
  3. const int maxn=100005;
  4. int i,j,k,m,n;
  5. int a[maxn];
  6. inline int max(int a,int b){
  7. return a>b? a:b;
  8. }
  9. struct SPLAY{
  10. int cnt,root;
  11. int val[maxn],chd[maxn][2],f[maxn],size[maxn],maxx[maxn];
  12. inline void init(){
  13. cnt=root=0;
  14. }
  15. inline int newnode(int x,int fth){
  16. size[++cnt]=1,chd[cnt][0]=0,chd[cnt][1]=0,val[cnt]=x,f[cnt]=fth;
  17. return cnt;
  18. }
  19. inline void pushup(int now){
  20. size[now]=size[chd[now][0]]+size[chd[now][1]]+1;
  21. maxx[now]=val[now];
  22. if(a[maxx[chd[now][0]]]>a[maxx[now]])
  23. maxx[now]=maxx[chd[now][0]];
  24. if(a[maxx[chd[now][1]]]>a[maxx[now]])
  25. maxx[now]=maxx[chd[now][1]];
  26. }
  27. inline int check(int now){
  28. return chd[f[now]][0]==now? 0:1;
  29. }
  30. inline void connect(int now,int son,int dir){
  31. f[son]=now,chd[now][dir]=son;
  32. }
  33. inline void rotate(int now){
  34. int fth=f[now],gfth=f[fth],frlt=check(now),grlt=check(fth);
  35. connect(gfth,now,grlt),connect(fth,chd[now][frlt^1],frlt),connect(now,fth,frlt^1);
  36. pushup(fth),pushup(now);
  37. }
  38. void splay(int now,int aim){
  39. while(f[now]!=aim){
  40. int fth=f[now],gfth=f[fth],frlt=check(now),grlt=check(fth);
  41. if(gfth!=aim)
  42. rotate(frlt^grlt? now:fth);
  43. rotate(now);
  44. }
  45. if(aim==0)
  46. root=now;
  47. }
  48. int getnum(int x){
  49. int now=root;
  50. while(now){
  51. if(x==size[chd[now][0]]+1)
  52. return now;
  53. if(x<=size[chd[now][0]])
  54. now=chd[now][0];
  55. else x-=size[chd[now][0]]+1,now=chd[now][1];
  56. }
  57. return now;
  58. }
  59. void insert(int &x,int lst,int v){
  60. if(x==0){
  61. x=newnode(v,lst);
  62. return ;
  63. }
  64. if(a[v]>a[val[x]]&&a[v]>a[maxx[chd[x][1]]])
  65. insert(chd[x][0],x,v);
  66. else insert(chd[x][1],x,v);
  67. pushup(x);
  68. }
  69. void work(int p,int c){
  70. if(p-c>1){
  71. splay(getnum(p-c-1),0);
  72. insert(chd[root][1],root,p);
  73. }
  74. else insert(root,0,p);
  75. splay(cnt,0);
  76. }
  77. void out(int x){
  78. if(chd[x][0])
  79. out(chd[x][0]);
  80. printf("%d ",val[x]);
  81. if(chd[x][1])
  82. out(chd[x][1]);
  83. }
  84. void write(){
  85. out(root);
  86. }
  87. }Splay;
  88. int main(){
  89. scanf("%d",&n);
  90. Splay.init();
  91. for(i=1;i<=n;i++){
  92. int c;
  93. scanf("%d%d",&a[i],&c);
  94. Splay.work(i,c);
  95. }
  96. Splay.write();
  97. return 0;
  98. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注