P2042 [NOI2005]维护数列

题意

题目描述

请写一个程序,要求维护一个数列,支持以下\(6\)种操作:(请注意,格式栏中的下划线‘_’表示实际输入文件中的空格)

输入输出格式

输入格式:

输入文件的第\(1\)行包含两个数\(N\)和\(M\),\(N\)表示初始时数列中数的个数,\(M\)表示要进行的操作数目。 第\(2\)行包含\(N\)个数字,描述初始时的数列。以下\(M\)行,每行一条命令,格式参见问题描述中的表格。

输出格式:

对于输入数据中的GET-SUMMAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

输入输出样例

输入样例#1:

  1. 9 8
  2. 2 -6 3 5 1 -5 -3 6 3
  3. GET-SUM 5 4
  4. MAX-SUM
  5. INSERT 8 3 -5 7 2
  6. DELETE 12 1
  7. MAKE-SAME 3 3 2
  8. REVERSE 3 6
  9. GET-SUM 5 4
  10. MAX-SUM

输出样例#1:

  1. -1
  2. 10
  3. 1
  4. 10

说明

你可以认为在任何时刻,数列中至少有\(1\)个数。

输入数据一定是正确的,即指定位置的数在数列中一定存在。

\(50\%\)的数据中,任何时刻数列中最多含有\(30000\)个数;

\(100\%\)的数据中,任何时刻数列中最多含有\(500000\)个数。

\(100\%\)的数据中,任何时刻数列中任何一个数字均在\([-1000,1000]\)内。

\(100\%\)的数据中,\(M\leq 20000\),插入的数字总数不超过\(4000000\)。

思路

平衡树板子题(其实没有那么板),调试的难度还是很大的。

\(fhq\ Treap\)的线性建树是我从这题学到的新定西,直接放代码吧:

  1. int build(int now)//新加入的点的数量
  2. {
  3. stack<int>S;//主要思想是维护一个单调栈
  4. int last;
  5. for(int i=1;i<=now;i++)
  6. {
  7. int x=new_node(a[i]);last=0;//新建结点
  8. while(!S.empty()&&rnd(S.top())>rnd(x)) last=S.top(),update(S.top()),S.pop();//维护小根堆,寻找新结点的父节点
  9. if(!S.empty()) rs(S.top())=x;
  10. ls(x)=last,S.push(x);//把刚刚弹出的结点再接上
  11. }
  12. while(!S.empty()) last=S.top(),update(S.top()),S.pop();
  13. return last;//返回新建树的根
  14. }

本题的第二个难点是内存回收,可以直接开一个队列记录被删除的点,新建结点时从队列中取就好了。

AC代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN=5e5+5;
  4. int n,m,rt,cnt,a[MAXN];
  5. bool H[MAXN];
  6. int read()
  7. {
  8. bool f=true;int re=0;char ch=getchar();
  9. while(!isdigit(ch)){if(ch=='-')f=false;ch=getchar();}
  10. while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
  11. return f?re:-re;
  12. }
  13. struct Node
  14. {
  15. int ls,rs,sz,val,rnd,sum;
  16. int sub_sum,left_sub_sum,right_sub_sum;
  17. int change_tag;
  18. bool reverse_tag;
  19. #define ls(a) node[a].ls
  20. #define rs(a) node[a].rs
  21. #define sz(a) node[a].sz
  22. #define val(a) node[a].val
  23. #define rnd(a) node[a].rnd
  24. #define sum(a) node[a].sum
  25. #define lsm(a) node[a].left_sub_sum
  26. #define rsm(a) node[a].right_sub_sum
  27. #define sub(a) node[a].sub_sum
  28. #define ctg(a) node[a].change_tag
  29. #define rtg(a) node[a].reverse_tag
  30. }node[MAXN];
  31. queue<int>dustbin;
  32. int new_node(int k)
  33. {
  34. int re;
  35. if(!dustbin.empty()) re=dustbin.front(),H[dustbin.front()]=false,dustbin.pop();
  36. else re=++cnt;
  37. ls(re)=rs(re)=0,sz(re)=1;
  38. val(re)=sum(re)=sub(re)=k;
  39. lsm(re)=rsm(re)=max(k,0);
  40. rnd(re)=rand();
  41. ctg(re)=INT_MAX,rtg(re)=false;
  42. return re;
  43. }
  44. void update(int now)
  45. {
  46. if(ls(now)&&rs(now))
  47. {
  48. sz(now)=sz(ls(now))+sz(rs(now))+1;
  49. sum(now)=sum(ls(now))+sum(rs(now))+val(now);
  50. lsm(now)=max(lsm(ls(now)),sum(ls(now))+val(now)+lsm(rs(now)));
  51. rsm(now)=max(rsm(rs(now)),sum(rs(now))+val(now)+rsm(ls(now)));
  52. sub(now)=max(max(sub(ls(now)),sub(rs(now))),rsm(ls(now))+val(now)+lsm(rs(now)));
  53. }
  54. else if(ls(now))
  55. {
  56. sz(now)=sz(ls(now))+1;
  57. sum(now)=sum(ls(now))+val(now);
  58. lsm(now)=max(max(lsm(ls(now)),sum(ls(now))+val(now)),0);
  59. rsm(now)=max(0,val(now)+rsm(ls(now)));
  60. sub(now)=max(sub(ls(now)),rsm(ls(now))+val(now));
  61. }
  62. else if(rs(now))
  63. {
  64. sz(now)=sz(rs(now))+1;
  65. sum(now)=sum(rs(now))+val(now);
  66. rsm(now)=max(max(rsm(rs(now)),sum(rs(now))+val(now)),0);
  67. lsm(now)=max(0,val(now)+lsm(rs(now)));
  68. sub(now)=max(sub(rs(now)),lsm(rs(now))+val(now));
  69. }
  70. else
  71. {
  72. sz(now)=1,sum(now)=sub(now)=val(now);
  73. lsm(now)=rsm(now)=max(val(now),0);
  74. }
  75. }
  76. void pushdown(int now)
  77. {
  78. if(rtg(now))
  79. {
  80. if(ls(now))
  81. {
  82. swap(ls(ls(now)),rs(ls(now)));
  83. swap(lsm(ls(now)),rsm(ls(now)));
  84. rtg(ls(now))^=1;
  85. }
  86. if(rs(now))
  87. {
  88. swap(ls(rs(now)),rs(rs(now)));
  89. swap(lsm(rs(now)),rsm(rs(now)));
  90. rtg(rs(now))^=1;
  91. }
  92. }
  93. if(ctg(now)!=INT_MAX)
  94. {
  95. if(ls(now))
  96. {
  97. sum(ls(now))=sz(ls(now))*ctg(now);
  98. val(ls(now))=ctg(now);
  99. lsm(ls(now))=rsm(ls(now))=max(sum(ls(now)),0);
  100. sub(ls(now))=max(val(ls(now)),sum(ls(now)));
  101. ctg(ls(now))=ctg(now);
  102. }
  103. if(rs(now))
  104. {
  105. sum(rs(now))=sz(rs(now))*ctg(now);
  106. val(rs(now))=ctg(now);
  107. lsm(rs(now))=rsm(rs(now))=max(sum(rs(now)),0);
  108. sub(rs(now))=max(val(rs(now)),sum(rs(now)));
  109. ctg(rs(now))=ctg(now);
  110. }
  111. }
  112. rtg(now)=false,ctg(now)=INT_MAX;
  113. }
  114. int merge(int x,int y)
  115. {
  116. if(x) pushdown(x);
  117. if(y) pushdown(y);
  118. if(!x||!y) return x+y;
  119. if(rnd(x)<rnd(y))
  120. {
  121. rs(x)=merge(rs(x),y);
  122. update(x);
  123. return x;
  124. }
  125. else
  126. {
  127. ls(y)=merge(x,ls(y));
  128. update(y);
  129. return y;
  130. }
  131. }
  132. void split(int now,int k,int &x,int &y)
  133. {
  134. if(!now) x=y=0;
  135. else
  136. {
  137. pushdown(now);
  138. if(sz(ls(now))>=k)
  139. {
  140. y=now;
  141. split(ls(y),k,x,ls(y));
  142. }
  143. else
  144. {
  145. x=now;
  146. split(rs(x),k-sz(ls(now))-1,rs(x),y);
  147. }
  148. update(now);
  149. }
  150. }
  151. void recycle(int now)
  152. {
  153. if(!H[now]) dustbin.push(now),H[now]=false;
  154. if(ls(now)) recycle(ls(now));
  155. if(rs(now)) recycle(rs(now));
  156. }
  157. int build(int now)
  158. {
  159. stack<int>S;
  160. int last;
  161. for(int i=1;i<=now;i++)
  162. {
  163. int x=new_node(a[i]);last=0;
  164. while(!S.empty()&&rnd(S.top())>rnd(x)) last=S.top(),update(S.top()),S.pop();
  165. if(!S.empty()) rs(S.top())=x;
  166. ls(x)=last,S.push(x);
  167. }
  168. while(!S.empty()) last=S.top(),update(S.top()),S.pop();
  169. return last;
  170. }
  171. int main()
  172. {
  173. srand(19260817);
  174. n=read(),m=read();
  175. for(int i=1;i<=n;i++) a[i]=read();
  176. rt=build(n);
  177. while(m--)
  178. {
  179. char opt[20];
  180. scanf("%s",opt);
  181. if(opt[0]=='I')
  182. {
  183. int x,y,p,t;
  184. p=read(),t=read();
  185. split(rt,p,x,y);
  186. for(int i=1;i<=t;i++) a[i]=read();
  187. rt=merge(merge(x,build(t)),y);
  188. }
  189. else if(opt[0]=='D')
  190. {
  191. int x,y,z,p,t;
  192. p=read(),t=read();
  193. split(rt,p-1,x,y);
  194. split(y,t,y,z);
  195. recycle(y);
  196. rt=merge(x,z);
  197. }
  198. else if(opt[0]=='R')
  199. {
  200. int x,y,z,p,t;
  201. p=read(),t=read();
  202. split(rt,p-1,x,y);
  203. split(y,t,y,z);
  204. swap(ls(y),rs(y));
  205. swap(lsm(y),rsm(y));
  206. rtg(y)^=1;
  207. rt=merge(merge(x,y),z);
  208. }
  209. else if(opt[0]=='G')
  210. {
  211. int x,y,z,p,t;
  212. p=read(),t=read();
  213. split(rt,p-1,x,y);
  214. split(y,t,y,z);
  215. printf("%d\n",sum(y));
  216. rt=merge(merge(x,y),z);
  217. }
  218. else if(opt[0]=='M')
  219. {
  220. if(opt[2]=='K')
  221. {
  222. int x,y,z,p,t,tmp;
  223. p=read(),t=read(),tmp=read();
  224. split(rt,p-1,x,y);
  225. split(y,t,y,z);
  226. ctg(y)=val(y)=tmp,sum(y)=sz(y)*ctg(y);
  227. lsm(y)=rsm(y)=sub(y)=max(val(y),sum(y));
  228. rt=merge(merge(x,y),z);
  229. }
  230. else if(opt[2]=='X') printf("%d\n",sub(rt));
  231. }
  232. }
  233. return 0;
  234. }

Luogu P2042 [NOI2005]维护数列(平衡树)的更多相关文章

  1. BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay)

    手动博客搬家: 本文发表于20180825 00:34:49, 原地址https://blog.csdn.net/suncongbo/article/details/82027387 题目链接: (l ...

  2. Luogu P2042 [NOI2005]维护数列

    题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线' _ '表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...

  3. 洛谷 P2042 [NOI2005]维护数列-Splay(插入 删除 修改 翻转 求和 最大的子序列)

    因为要讲座,随便写一下,等讲完有时间好好写一篇splay的博客. 先直接上题目然后贴代码,具体讲解都写代码里了. 参考的博客等的链接都贴代码里了,有空再好好写. P2042 [NOI2005]维护数列 ...

  4. P2042 [NOI2005]维护数列[splay或非旋treap·毒瘤题]

    P2042 [NOI2005]维护数列 数列区间和,最大子列和(必须不为空),支持翻转.修改值.插入删除. 练码力的题,很毒瘤.个人因为太菜了,对splay极其生疏,犯了大量错误,在此记录,望以后一定 ...

  5. P2042 [NOI2005]维护数列 && Splay区间操作(四)

    到这里 \(A\) 了这题, \(Splay\) 就能算入好门了吧. 今天是个特殊的日子, \(NOI\) 出成绩, 大佬 \(Cu\) 不敢相信这一切这么快, 一下子机房就只剩我和 \(zrs\) ...

  6. [NOI2005]维护数列——平衡树观止

    本题题解并不详细,不推荐大家看这一篇. 可以看这篇 题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 100%的数据中, ...

  7. 洛谷P2042 [NOI2005]维护数列

    #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #in ...

  8. P2042 [NOI2005]维护数列

    思路 超级恶心的pushdown 昏天黑地的调 让我想起了我那前几个月的线段树2 错误 这恶心的一道题终于过了 太多错误,简直说不过来 pushup pushdown 主要就是这俩不太清晰,乱push ...

  9. 数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列

    339. [NOI2005] 维护数列 时间限制:3 s   内存限制:256 MB [问题描述] 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际 ...

随机推荐

  1. Java-Class-@I:org.apache.ibatis.annotations.Mapper

    ylbtech-Java-Class-@I:org.apache.ibatis.annotations.Mapper 1.返回顶部   2.返回顶部 1. package com.ylbtech.ed ...

  2. Redis消息订阅与发布

    监听器的创建 package com.sogou.baike.testimport.testSubscribe; import redis.clients.jedis.JedisPubSub; pub ...

  3. ES6 学习 -- 解构赋值

    一.数组解构 **数组解构,解构出来的值跟数组下标是一一对应的,如果左边变量多于右边数组,则左边后面部分变量值为undefined,如果右边数组元素个数多于左边解构变量个数,则左边变量全都有值,且一一 ...

  4. java oop第06章_异常处理

    一. 异常的概念: 若程序都按我们事先设定的计划运行为正常执行,但通常会出现我们事先预料之外的其他情况,称为程序发生异常, 在java中会对一些可能出现异常的代码进行分类,达到尽量对可能发生的异常进行 ...

  5. exe4j 打包(多个jar打包)

    一,自行下载exe4j 注册码: 用户名和公司名可随便填A-XVK258563F-1p4lv7mg7savA-XVK209982F-1y0i3h4ywx2h1A-XVK267351F-dpurrhny ...

  6. MySQL入门基础知识

    1.MySQL环境变量的配置 操作数据库时,要进入bin目录,如下: 但是如果进行配置环境变量,就不必切换路径,如下图所示,即使没有在G:\mysql-8.0.16-winx64\bin下,数据库依然 ...

  7. sleep()与wait()的区别

    ①sleep()实现线程阻塞的方法,我们称之为“线程睡眠”,方式是超时等待,怎么理解?就是sleep()通过传入“睡眠时间”作为方法的参数,时间一到就从“睡眠”中“醒来”: ②wait()方法实现线程 ...

  8. error while loading shared libraries: lib*.so: cannot open shared object file: No such file or directory

    动态库的搜索路径搜索的先后顺序是: 1.编译目标代码时指定的动态库搜索路径; 2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径: 比如export LD_LIBRARY_PATH=/us ...

  9. Maven - Scope区别

    依赖的Scope scope定义了类包在项目的使用阶段.项目阶段包括: 编译,运行,测试和发布. 分类说明 compile 默认scope为compile,表示为当前依赖参与项目的编译.测试和运行阶段 ...

  10. Java 基础 - 原生类型

    更详细的说明,请参考: Java 原生类型与包装器类型深度剖析,https://blog.csdn.net/justloveyou_/article/details/52651211 一. 原生类型与 ...