Description

Input

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

Output

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

Sample Input

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

Sample Output

-1
10
1
10

HINT

Source

【分析】
发现大家都是用splay做的,觉得用块状链表好像也可以做,结果真的可以....,捣鼓了一个下午,终于弄出来了.....
其实想好了还是很简单的(那你还做了一个下午,太弱了)。
用论文上的方法进行删除和添加数值,虽然效率有点低下,但是对付这道题还是够了。
因为没有牵涉到合并,因此不会涉及到标记的合并等等。
其实牵涉到了也没关系.....update一下就可以暴力合并,复杂度不会上升。
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cstring>
  5. #include <vector>
  6. #include <utility>
  7. #include <iomanip>
  8. #include <string>
  9. #include <cmath>
  10. #include <queue>
  11. #include <assert.h>
  12. #include <map>
  13. #include <ctime>
  14. #include <cstdlib>
  15.  
  16. const int MAXN = ;
  17. const int INF = ;
  18. const int SIZE = ;
  19. using namespace std;
  20. struct Node{
  21. int shu[SIZE+];
  22. int size, sum, samen;
  23. int lmax, rmax, mmax;
  24. Node *l, *r;
  25. bool turn, same;
  26.  
  27. Node(){//构造函数
  28. size = sum = samen = same = ;
  29. lmax = rmax = mmax = -INF;
  30. l = r = NULL;
  31. turn = ;
  32. }
  33. //对于两个较小的数列合并也要update
  34. void update(){
  35. if (same){//是否改为同样的
  36. for (int i = ; i <= size; i++) shu[i] = samen;
  37. turn = ;same = ;
  38. return;
  39. }
  40. if (!turn){//反转序列
  41. for (int i = ; i <= (size>>);i++) swap(shu[i], shu[size - i + ]);
  42. swap(lmax, rmax);
  43. turn = ;
  44. }
  45. }
  46. void Count(){
  47. update();
  48. int t = ;
  49. sum = ;
  50. rmax = lmax = mmax = -INF;
  51. //序列中间的一段和
  52. for (int i = ; i <= size; i++){
  53. sum += shu[i];
  54. t = max(t + shu[i], shu[i]);
  55. mmax = max(t, mmax);
  56. }
  57. t = ;
  58. for (int i = ; i <= size; i++) {t += shu[i]; lmax = max(lmax, t);}t = ;
  59. for (int i = size; i >= ; i--) {t += shu[i]; rmax = max(rmax, t);}
  60. }
  61. };
  62. //块状链表
  63. struct Block{
  64. Node *head, *p;
  65. int dir;
  66.  
  67. Block(){head = new Node;}
  68. void find(int x){//移动到x所在的块,顺便压缩路径
  69. int tmp = ;
  70. p = head;
  71. while (p->size + tmp < x){
  72. tmp += p->size;
  73. if (p->size == ){
  74. p = p->l;
  75. p->r = p->r->r;
  76. if (p->r != NULL) p->r->l = p;
  77. }
  78. p = p->r;
  79. }
  80. dir = x - tmp;
  81. }
  82. //将a分成a和b两个块
  83. Node *NEW(Node *&a){
  84. Node *b = new Node;
  85. b->r = a->r;
  86. b->l = a;
  87. if (a->r != NULL) a->r->l = b;
  88. a->r = b;
  89. return b;
  90. }
  91. void Insert(int pos,int size,int *data){ //插入操作
  92. Node *p2;
  93. find(pos);
  94. p->update();
  95. //如果指向中间,就分裂,注意这一段在开头也同样可以操作!
  96. if (dir != p->size){
  97. //这种操作与普通的块状链表有点不一样,但是更加便于理解
  98. p2 = NEW(p);
  99. memcpy(&p2->shu[], &p->shu[dir + ], sizeof(int) * (p->size - dir));
  100.  
  101. p2->size = p->size - dir;
  102. p->size = dir;
  103.  
  104. p2->Count();
  105. p->Count();
  106. }
  107. int i = ;//插入数列
  108. while (i <= size){
  109. int tmp = min( - p->size, size - i + );
  110. memcpy(&p->shu[p->size + ], &data[i], sizeof(int)*tmp);
  111. i += tmp;
  112. p->size += tmp;
  113. if (size >= i){//创建新的列表再加入
  114. p->Count();
  115. p2 = NEW(p);
  116. p = p2;
  117. }
  118. }
  119. p->Count();
  120. }
  121. void Delete(int pos,int num){
  122. Node *p2;
  123. find(pos);
  124. while (num > ){
  125. if ((dir == ) && (num >= p->size)){
  126. //删除一个块
  127. num -= p->size;
  128. if (p->l != NULL) p->l->r = p->r;
  129. else head = p->r;//不然就是表头
  130. if (p->r != NULL) p->r->l = p->l;
  131. p2 = p;
  132. p = p->r;
  133. delete p2;
  134. }else{//暴力删除直到一个块
  135. p->update();
  136. //tmp记录能删除的最远位置
  137. int tmp = min(dir + num - , p->size);
  138. num -= tmp - dir + ;
  139. for (int i = ; i <= p->size - tmp; i++) p->shu[dir + i - ] = p->shu[tmp + i];
  140. p->size -= tmp - dir + ;
  141. p->Count();
  142. p = p->r;
  143. dir = ;
  144. }
  145. }
  146. }
  147. //反转操作
  148. void Reverse(int pos, int num){
  149. Node *ap,*bp,*cp,*dp;
  150. Node *p2;
  151. bool first=true;
  152. int tmp;
  153. find(pos);
  154.  
  155. if (p->size >= dir + num - ){//直接暴力
  156. p->update();
  157. for (int i = ; i <= (num >> ); i++) swap(p->shu[dir + num - i], p->shu[dir + i - ]);
  158. p->Count();
  159. return;
  160. }
  161. if (dir > ){//拆第一块
  162. p->update();
  163. num -= p->size - dir + ;
  164. p2 = NEW(p);
  165. memcpy(&p2->shu[], &p->shu[dir], sizeof(int)*(p->size-dir+));
  166. p2->size = p->size - dir + ;
  167. p->size = dir - ;
  168.  
  169. ap = p2;
  170. cp = p;
  171. p2->Count();
  172. p->Count();
  173. p = p2->r;
  174. }else{
  175. ap = p;
  176. cp = ap->l;
  177. }
  178. while (num > p->size){
  179. num -= p->size;
  180. p = p->r;
  181. }
  182. //最后一块也要拆
  183. if (num != p->size){
  184. p->update();
  185. p2 = NEW(p);
  186. memcpy(&p2->shu[],&p->shu[num+],sizeof(int)*(p->size-num));
  187. p2->size = p->size - num;
  188. p->size = num;
  189.  
  190. bp = p;
  191. dp = p2;
  192. p2->Count();
  193. p->Count();
  194. }else{
  195. //简单的反转一下
  196. bp = p;
  197. dp = p->r;
  198. }
  199. //从开头开始大反转
  200. p = ap;
  201. while (){
  202. swap(p->l, p->r);
  203. p->turn = !p->turn;
  204. swap(p->lmax, p->rmax);
  205. if (p == bp) break;
  206. p = p->l;//注意因为已经换了所以是向左走
  207. }
  208. //将整个块倒转
  209. if (cp != NULL) cp->r = bp;
  210. else head = bp;
  211. ap->r = dp;
  212. bp->l = cp;
  213. if (dp != NULL) {dp->l = ap;}
  214. }
  215. //使一段序列变成相同的值
  216. void MakeSame(int pos,int num,int val){
  217. find(pos);
  218. while (num > ){
  219. if ((dir == ) && (num >= p->size)){
  220. //整块操作
  221. p->same = ;
  222. p->samen = val;
  223. p->sum = p->size * val;
  224. p->mmax = max(val, p->sum);//注意因为val可能是负数,所以要这样写
  225. p->rmax = p->lmax = p->mmax;
  226. num -= p->size;
  227. p = p->r;
  228. }else{
  229. p->update();//暴力操作
  230. int tmp = min(dir + num - , p->size);
  231. for (int i = dir; i <= tmp; i++) p->shu[i] = val;
  232. p->Count();
  233. num -= tmp - dir + ;
  234. p = p->r;
  235. dir = ;
  236. }
  237. }
  238. }
  239. //区间和
  240. int GetSum(int pos,int x){
  241. int tmp = ;
  242. find(pos);
  243. while (x > ){
  244. if ((dir == ) && (x >= p->size)){
  245. tmp += p->sum;
  246. x -= p->size;
  247. p = p->r;
  248. }else{ //暴力
  249. p->Count();
  250. int t = min(dir + x - , p->size);
  251. for (int i = dir; i <= t; i++) tmp += p->shu[i];
  252. x -= t - dir + ;
  253. p = p->r;
  254. dir = ;
  255. }
  256. }
  257. return tmp;
  258. }
  259. //区间最大值
  260. int MaxSum(){
  261. int Ans = -INF, last = -INF;
  262. p = head;
  263. while (p != NULL){
  264. if (p->size != ){
  265. int tmp;
  266. tmp = max(last + p->sum, max(p->rmax, p->sum));
  267. Ans = max(Ans, max(last + p->lmax, max(tmp, p->mmax)));
  268. last = tmp;
  269. }
  270. p = p->r;
  271. }
  272. return Ans;
  273. }
  274. }A;
  275.  
  276. int m, pos;
  277. int n,tmp, data[MAXN];
  278. char str[];
  279.  
  280. void init(){
  281. scanf("%d%d", &n, &m);
  282. for (int i = ; i <= n; i++) scanf("%d", &data[i]);
  283. tmp = ;
  284. A.Insert(tmp, n, data);
  285. }
  286. void work(){
  287. for (int i = ; i <= m; i++){
  288. scanf("%s", str);
  289. if (str[] != 'X') scanf("%d%d", &pos, &n);
  290. if (str[] == 'S'){
  291. for (int i = ; i <= n; i++) scanf("%d", &data[i]);
  292. A.Insert(pos, n, data);
  293. }else if (str[] == 'L') A.Delete(pos, n);
  294. else if (str[] == 'K') {
  295. int tmp;
  296. scanf("%d", &tmp);
  297. A.MakeSame(pos, n, tmp);
  298. }else if (str[] == 'T') printf("%d\n", A.GetSum(pos, n));
  299. else if (str[] == 'V') A.Reverse(pos,n);
  300. else if (str[] == 'X') printf("%d\n", A.MaxSum());
  301. }
  302. }
  303.  
  304. int main(){
  305. #ifdef LOCAL
  306. freopen("data.txt", "r", stdin);
  307. freopen("out.txt", "w", stdout);
  308. #endif
  309. init();
  310. work();
  311. return ;
  312. }

【BZOJ1500】【块状链表】维修数列的更多相关文章

  1. 【BZOJ1500】[NOI2005]维修数列 Splay

    [BZOJ1500][NOI2005]维修数列 Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行 ...

  2. 【BZOJ1500】[NOI2005]维修数列

    Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一 ...

  3. BZOJ1500:[NOI2005]维修数列——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=1500 https://www.luogu.org/problemnew/show/P2042#su ...

  4. BZOJ1500:[NOI2005]维修数列

    浅谈\(splay\):https://www.cnblogs.com/AKMer/p/9979592.html 浅谈\(fhq\)_\(treap\):https://www.cnblogs.com ...

  5. [BZOJ1500][NOI2005]维修数列---解题报告

    Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...

  6. 【BZOJ1500】【NOI2005】维修数列(Splay)

    [BZOJ1500][NOI2005]维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream ...

  7. [BZOJ1500][NOI2005]维修数列 解题报告 Splay

    Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...

  8. [bzoj1500][NOI2005]维修数列_非旋转Treap

    维修数列 bzoj-1500 NOI-2005 题目大意:给定n个数,m个操作,支持:在指定位置插入一段数:删除一个数:区间修改:区间翻转.查询:区间和:全局最大子序列. 注释:$1\le n_{ma ...

  9. 【BZOJ-1500】维修数列 Splay

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 11047  Solved: 3460[Submit][Statu ...

随机推荐

  1. vijosP1285 佳佳的魔法药水

    vijosP1285 佳佳的魔法药水 链接:https://vijos.org/p/1285 [思路] 图论思想. 很巧妙. 如A+B=C,将AB之间连边,边权为C,用以找相连物品与合成物. 用Dij ...

  2. jQuery 遍历

    .add() add() 方法将元素添加到匹配元素的集合中 .add(selector)//字符串值,表示查找供添加到匹配元素集合的元素的选择器表达式. .add(elements)//添加到匹配元素 ...

  3. (转载)ASP网站如何防止注入漏洞攻击

    SQL注入是从正常的WWW端口访问,而且表面看起来跟一般的Web页面访问没什么区别,所以目前市面的防火墙都不会对SQL注入发出警报,如 果管理员没查看IIS日志的习惯,可能被入侵很长时间都不会发觉.但 ...

  4. lightoj1051 Good and Bad (dp)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1051 题目大意:给你一个字符串,只包含大写字母和‘?’,如果字符串中出现了连续三个以上 ...

  5. python 2 处理HTTP 请求的包

    httplib httplib: https://docs.python.org/2/library/httplib.html python 的官方文档这样说明: This module define ...

  6. JAVA wait(), notify(),sleep详解

    转自: http://blog.csdn.net/zyplus 在JAVA中,是没有类似于PV操作.进程互斥等相关的方法的.JAVA的进程同步是通过synchronized()来实现的,需要说明的是, ...

  7. 如何选择NoSql数据库

    How to choose a No Sql database 介绍了一下怎么选择一个No Sql数据库,下面简单翻译一下重点. No Sql的数据库可以分为如下4类: Key-Value数据库 数据 ...

  8. 【Android - MD】之TextInputLayout的使用

    TextInputLayout是Android 5.0新特性--Material Design中的一个布局控件,主要用来嵌套EditText,实现数据输入时的一些效果,如: 当输入框获取焦点时,输入提 ...

  9. [置顶] 获取激活码,激活myeclipse

    myeclipse10.0 正式版下载地址: http://downloads.myeclipseide.com/downloads/products/eworkbench/indigo/instal ...

  10. MySQL内存体系架构及参数总结 ---图解

    http://www.cnblogs.com/kissdb/p/4009614.html 内存结构: Mysql 内存分配规则是:用多少给多少,最高到配置的值,不是立即分配 图只做大概参考 全局缓存包 ...