终于把区间操作的Splay搞明白了……

Splay的大致框架是这样的:

【代码中的Zig-Zig和Zig-Zag操作其实是可以优化的,实际只需要3次passDown和3次update】

  1. template <class T>
  2. struct SplayNode
  3. {
  4. typedef SplayNode<T> Node;
  5. Node* lch;
  6. Node* rch;
  7. Node* parent;
  8. T val;
  9.  
  10. SplayNode(const T& _val,Node* _parent):
  11. lch(),rch(),parent(_parent),val(_val) {}
  12.  
  13. void passDown() {}
  14. void update() {}
  15.  
  16. void lRotate()
  17. {
  18. if(parent->parent)
  19. {
  20. if(parent==parent->parent->lch)
  21. parent->parent->lch=this;
  22. else parent->parent->rch=this;
  23. }
  24.  
  25. parent->passDown();
  26. passDown();
  27.  
  28. parent->rch=this->lch;
  29. if(lch) lch->parent=this->parent;
  30.  
  31. lch=parent;
  32. parent=parent->parent;
  33. lch->parent=this;
  34.  
  35. lch->update();
  36. update();
  37. }
  38.  
  39. void rRotate()
  40. {
  41. if(parent->parent)
  42. {
  43. if(parent==parent->parent->lch)
  44. parent->parent->lch=this;
  45. else parent->parent->rch=this;
  46. }
  47.  
  48. parent->passDown();
  49. passDown();
  50.  
  51. parent->lch=this->rch;
  52. if(rch) rch->parent=this->parent;
  53.  
  54. rch=parent;
  55. parent=parent->parent;
  56. rch->parent=this;
  57.  
  58. rch->update();
  59. update();
  60. }
  61.  
  62. Node* splay()
  63. {
  64. while(parent)
  65. {
  66. ;
  67. ; ;
  68. if(parent->parent)
  69. {
  70. ;
  71. ;
  72. }
  73.  
  74. switch(status)
  75. {
  76. : rRotate(); break;
  77. : lRotate(); break;
  78. : parent->rRotate(); this->rRotate(); break;
  79. : lRotate(); rRotate(); break;
  80. : rRotate(); lRotate(); break;
  81. : parent->lRotate(); this->lRotate(); break;
  82. }
  83. }
  84. return this;
  85. }
  86. };

注意双旋的Zig-Zig(Zag-Zag)和Zig-Zag(Zag-Zig),后者可以分解成两次单旋,而前者不能。

借教室一题的85分代码(Vijos):

(Splay果然常数大……当然很可能是我写萎了……)

  1. #include <algorithm>
  2.  
  3. using std::max;
  4. using std::min;
  5.  
  6. struct SplayNode
  7. {
  8. typedef SplayNode Node;
  9. Node* lch;
  10. Node* rch;
  11. Node* parent;
  12.  
  13. int idx;
  14. int val;
  15. int minVal;
  16. int lazyTag;
  17.  
  18. SplayNode() {}
  19.  
  20. SplayNode(int _idx,int _val,Node* _parent):
  21. lch(),rch(),parent(_parent),idx(_idx),val(_val),
  22. minVal(_val),lazyTag() {}
  23.  
  24. void assign(int _idx,int _val,int _minVal,Node* _rch,Node* _parent)
  25. {
  26. idx=_idx;
  27. val=_val;
  28. minVal=_minVal;
  29. lazyTag=;
  30. lch=;
  31. rch=_rch;
  32. parent=_parent;
  33. }
  34.  
  35. int actual() { return minVal + lazyTag; }
  36.  
  37. void passDown()
  38. {
  39. if(!lazyTag) return;
  40.  
  41. if(lch) lch->lazyTag += this->lazyTag;
  42. if(rch) rch->lazyTag += this->lazyTag;
  43.  
  44. val += lazyTag;
  45. minVal += lazyTag;
  46. lazyTag = ;
  47. }
  48.  
  49. void update()
  50. {
  51. minVal = lch ?
  52. ( rch ? min(min(lch->actual(),rch->actual()),this->val) :
  53. min(lch->actual(),this->val) ) :
  54. ( rch ? min(rch->actual(),this->val) : this->val );
  55. }
  56.  
  57. void lRotate()
  58. {
  59. if(parent->parent)
  60. {
  61. if(parent==parent->parent->lch)
  62. parent->parent->lch=this;
  63. else parent->parent->rch=this;
  64. }
  65.  
  66. parent->passDown();
  67. passDown();
  68.  
  69. parent->rch=this->lch;
  70. if(lch) lch->parent=this->parent;
  71.  
  72. lch=parent;
  73. parent=parent->parent;
  74. lch->parent=this;
  75.  
  76. lch->update();
  77. update();
  78. }
  79.  
  80. void rRotate()
  81. {
  82. if(parent->parent)
  83. {
  84. if(parent==parent->parent->lch)
  85. parent->parent->lch=this;
  86. else parent->parent->rch=this;
  87. }
  88.  
  89. parent->passDown();
  90. passDown();
  91.  
  92. parent->lch=this->rch;
  93. if(rch) rch->parent=this->parent;
  94.  
  95. rch=parent;
  96. parent=parent->parent;
  97. rch->parent=this;
  98.  
  99. rch->update();
  100. update();
  101. }
  102.  
  103. Node* splay()
  104. {
  105. while(parent)
  106. {
  107. ;
  108. ; ;
  109. if(parent->parent)
  110. {
  111. ;
  112. ;
  113. }
  114.  
  115. switch(status)
  116. {
  117. : rRotate(); break;
  118. : lRotate(); break;
  119. : parent->rRotate(); this->rRotate(); break;
  120. : lRotate(); rRotate(); break;
  121. : rRotate(); lRotate(); break;
  122. : parent->lRotate(); this->lRotate(); break;
  123. }
  124. }
  125. return this;
  126. }
  127. };
  128.  
  129. ;
  130.  
  131. SplayNode node[maxN];
  132. int n,m;
  133.  
  134. int change(int d,int s,int t)
  135. {
  136. ;
  137. ) status |= ;
  138. ;
  139.  
  140. switch(status)
  141. {
  142. :
  143. node[s-].splay();
  144. node[s-].rch->parent=;
  145. node[t+].splay();
  146. node[s-].rch=&node[t+];
  147. node[t+].parent=&node[s-];
  148.  
  149. node[t+].lch->lazyTag -= d;
  150. node[t+].update();
  151. node[s-].update();
  152. ;
  153. :
  154. node[t+].splay();
  155. node[t+].lch->lazyTag -= d;
  156. node[t+].update();
  157. ;
  158. :
  159. node[s-].splay();
  160. node[s-].rch->lazyTag -= d;
  161. node[s-].update();
  162. ;
  163. :
  164. node[].splay();
  165. node[].val -= d;
  166. node[].minVal -= d;
  167. ].rch) node[].rch->lazyTag -= d;
  168. ;
  169. }
  170. }
  171.  
  172. #include <cstdarg>
  173. #include <cstdio>
  174. #include <cctype>
  175.  
  176. void readInt(int argCnt,...)
  177. {
  178. va_list va;
  179. va_start(va,argCnt);
  180.  
  181. while(argCnt--)
  182. {
  183. int* dest=va_arg(va,int*);
  184. ;
  185. char curDigit;
  186.  
  187. do curDigit=getchar(); while(!isdigit(curDigit));
  188. while(isdigit(curDigit))
  189. {
  190. destVal = destVal * + curDigit - ';
  191. curDigit=getchar();
  192. }
  193. *dest=destVal;
  194. }
  195.  
  196. va_end(va);
  197. }
  198.  
  199. int avai[maxN];
  200.  
  201. int main()
  202. {
  203. readInt(,&n,&m);
  204.  
  205. ;i<=n;++i) readInt(,avai+i);
  206.  
  207. for(int i=n;i;--i)
  208. {
  209. ,&node[i-]);
  210. ) node[i].assign(n,avai[i],min(avai[i],node[i+].minVal),&node[i+],);
  211. ].minVal),&node[i+],&node[i-]);
  212. }
  213.  
  214. ;i<=m;i++)
  215. {
  216. int d,s,t;
  217. readInt(,&d,&s,&t);
  218. int rt=change(d,s,t);
  219. )
  220. {
  221. printf("-1\n%d",i);
  222. ;
  223. }
  224. }
  225. printf(");
  226. ;
  227. }

修正了一点失误+改成了静态内存

(也许出题人没想到有人会用splay写这道题,所以之前的错误居然没被查出来……)

对于这道题,我们需要给每个Node额外设立3个域:idx(教室的标号,作为键值),minVal(子树中val的最小值),和lazyTag(修改的懒惰标记)

对区间[L,R]进行修改时,首先将L-1提到根,然后将R+1提到根的右孩子处,那么R+1的左孩子就是待修改的区间

当然要特判L==1和R==n(即左/右端为边界的情况)

注意旋转过程中要不断下传lazyTag并对节点的minVal值更新

(这个超级麻烦,一定要把每个细节都想全了,稍有一点疏忽就会出错,而且很不好查)

询问时直接询问根节点的minVal值即可(注意要让根节点的lazyTag传下去)

NOIP2012 借教室 Splay初探的更多相关文章

  1. NOIP2012借教室[线段树|离线 差分 二分答案]

    题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自 ...

  2. NC16564 [NOIP2012]借教室

    NC16564 [NOIP2012]借教室 题目 题目描述 ​ 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借 ...

  3. NOIP2012 借教室

    描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样.面对海量租借教室的信息,我们自然希望编 ...

  4. NOIP2012借教室

    题目描述 Description 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海 ...

  5. 【洛谷P1083】[NOIP2012]借教室

    借教室 [题目描述] 在n天中每天有一个可以借出的教室数,有m个订单,每个订单从第l天到第r天要借用x个教室.问能否满足所有的订单,若不能,输出第一个不能满足的订单编号. 思路: 1.1 ≤ n,m ...

  6. [NOIP2012]借教室 题解

    题目大意: 有一个n个数的数列,m个操作,第i个操作使[li,ri]区间建di,问第几个操作使数列中出现负数. 思路: 暴力显然过不了,那么就可以优化了,不难想到线段树,显然需要良好的姿势,那么就差分 ...

  7. luogu1083 [NOIp2012]借教室 (二分答案+差分)

    先二分一个答案x,然后通过差分来看有没有不满足的 #include<bits/stdc++.h> #define pa pair<int,int> #define lowb(x ...

  8. NOIP2012 借教室 题解 洛谷P1083

    一看就是暴力 好吧,其实是线段树或差分+二分,这里用的是差分+二分的做法. 二分部分的代码,套个二分板子就行 ,right=m; while(left<right)//二分 { ; ; else ...

  9. 洛谷 1083 (NOIp2012) 借教室——标记永久化线段树 / 差分+二分

    题目:https://www.luogu.org/problemnew/show/P1083 听说线段树不标记永久化会T一个点. 注意mn记录的是本层以下.带上标记的min! #include< ...

随机推荐

  1. 【转】实现展开列ExpandableListView的三种方式之SimpleExpandableListAdapter实例

    原文网址:http://blog.csdn.net/x605940745/article/details/12099709 实现可扩展展开列ExpandableListView的三种方式 欢迎加入QQ ...

  2. (转载)PHP json_encode() 函数介绍

    (转载) 在 php 中使用 json_encode() 内置函数(php > 5.2)可以使用得 php 中数据可以与其它语言很好的传递并且使用它. 这个函数的功能是将数值转换成json数据存 ...

  3. 性能指标--并发用户数(Concurrent Users)

    并发用户数是指:在某一时间点,与被测目标系统同时进行交互的客户端用户的数量. 并发用户数有以下几种含义: 1. 并发虚拟用户数(Concurrent Virtual Users,Users_CVU) ...

  4. 用Delphi制作仿每行带按钮的列表

    Delphi做程序开发在使用到列表控件时,一般是列表放文本内容,在列表以外放操作按钮,选中列表某项再点按钮进行操作.现在Web开发做列表的样式总是列表的每行都有操作按钮,如微博的列表风格: Web开发 ...

  5. 邮件发送小demo

    //send email public static bool SendEmail() { //实例化发件人地址 MailAddress from = new MailAddress("aa ...

  6. Hdu 4010-Query on The Trees LCT,动态树

    Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Othe ...

  7. [ReadingNotes] Search the links, static final in the java

    [ReadingNotes] Search the links, static final in the java */--> pre { background-color: #2f4f4f;l ...

  8. php写excel

    $this->loadexcel();        $objPHPExcel = new PHPExcel();        $objPHPExcel->getProperties() ...

  9. VShell破解版

    VShell破解版 VShell破解版

  10. Java内部类的一些总结

    作为刚入门Java的小白,这两天看到内部类,这里做一个总结,若有错误,欢迎指正~ 内部类是指在一个外部类的内部再定义一个类.类名不需要和文件夹相同. 内部类分为: 成员内部类.局部内部类.静态嵌套类. ...