bzoj1500[NOI2005]维修数列
Posted GXZlegend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1500[NOI2005]维修数列相关的知识,希望对你有一定的参考价值。
题目描述
输入
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
输出
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
样例输入
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
样例输出
-1
10
1
10
题解
做了4小时的Splay“裸题”。
大概就是各种细节处理一下就行了。
这里ls和rs的数的个数可以为0,但ts的数的个数一定大于0,应该可以在代码中pushup部分理解。
ts[0]要赋成极小值,否则pushup时可能会因使用到0节点而不为真正值。
当某数为负数时,ls和rs为0,但是ts为v,即小于0。这点在pushdown中尤其突出。
pushdown中有无儿子的问题,一定要判断。
不能开特大空间,所以需要循环利用下标,把能用的下标存到一个队列中,加入时取出队首,删除时加到队尾。
搞定细节以后(话说不是先敲大体在搞细节吗),就是splay裸题。
220行丑丑的代码。。
#include <cstdio> #include <cstring> #include <queue> #define N 600010 using namespace std; int sum[N] , v[N] , ls[N] , rs[N] , ts[N] , si[N] , rev[N] , tag[N] , c[2][N] , fa[N] , root; char str[20]; queue<int> q; inline int read() { int num = 0 , f = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘){if(ch == ‘-‘)f = -1; ch = getchar();} while(ch >= ‘0‘ && ch <= ‘9‘) num = (num << 3) + (num << 1) + ch - ‘0‘ , ch = getchar(); return num * f; } void pushup(int k) { int l = c[0][k] , r = c[1][k]; sum[k] = sum[l] + sum[r] + v[k]; ls[k] = max(ls[l] , sum[l] + v[k] + ls[r]); rs[k] = max(rs[r] , sum[r] + v[k] + rs[l]); ts[k] = max(max(ts[l] , ts[r]) , rs[l] + v[k] + ls[r]); si[k] = si[l] + si[r] + 1; } void pushdown(int k) { int l = c[0][k] , r = c[1][k]; if(tag[k] != 0x3f3f3f3f) { if(l) sum[l] = si[l] * tag[k] , v[l] = tag[l] = tag[k]; if(r) sum[r] = si[r] * tag[k] , v[r] = tag[r] = tag[k]; if(tag[k] > 0) { if(l) ls[l] = rs[l] = ts[l] = si[l] * tag[k]; if(r) ls[r] = rs[r] = ts[r] = si[r] * tag[k]; } else { if(l) ls[l] = rs[l] = 0 , ts[l] = tag[k]; if(r) ls[r] = rs[r] = 0 , ts[r] = tag[k]; } tag[k] = 0x3f3f3f3f; } if(rev[k]) { swap(c[0][l] , c[1][l]); swap(c[0][r] , c[1][r]); swap(ls[l] , rs[l]); swap(ls[r] , rs[r]); rev[l] ^= 1; rev[r] ^= 1; rev[k] = 0; } } void build(int l , int r , int f) { if(l > r) return; int mid = (l + r) >> 1; build(l , mid - 1 , mid); build(mid + 1 , r , mid); fa[mid] = f; c[mid > f][f] = mid; pushup(mid); } void rotate(int &k , int x) { int y = fa[x] , z = fa[y] , l , r; l = (c[0][y] != x); r = l ^ 1; if(y == k) k = x; else if(c[0][z] == y) c[0][z] = x; else c[1][z] = x; fa[x] = z; fa[y] = x; fa[c[r][x]] = y; c[l][y] = c[r][x]; c[r][x] = y; pushup(y); pushup(x); } void splay(int &k , int x) { while(k != x) { int y = fa[x] , z = fa[y]; if(y != k) { if(c[0][z] == y ^ c[0][y] == x) rotate(k , x); else rotate(k , y); } rotate(k , x); } } int find(int k , int x) { pushdown(k); if(x <= si[c[0][k]]) return find(c[0][k] , x); else if(x > si[c[0][k]] + 1) return find(c[1][k] , x - si[c[0][k]] - 1); else return k; } void update(int l , int r , int x) { int ta , tb , t; ta = find(root , l - 1); splay(root , ta); tb = find(root , r + 1); splay(c[1][root] , tb); t = c[0][c[1][root]]; sum[t] = si[t] * x; if(x > 0) ls[t] = rs[t] = ts[t] = si[t] * x; else ls[t] = rs[t] = 0 , ts[t] = x; v[t] = tag[t] = x; pushup(c[1][root]); pushup(root); } void rever(int l , int r) { int ta , tb , t; ta = find(root , l - 1); splay(root , ta); tb = find(root , r + 1); splay(c[1][root] , tb); t = c[0][c[1][root]]; swap(c[0][t] , c[1][t]); swap(ls[t] , rs[t]); rev[t] ^= 1; } void cls(int k) { if(k) { int l = c[0][k] , r = c[1][k]; cls(l) , q.push(k) , cls(r); tag[k] = 0x3f3f3f3f; rev[k] = sum[k] = si[k] = ls[k] = rs[k] = ts[k] = c[0][k] = c[1][k] = fa[k] = 0; } } int main() { int n , m , i , p , t , x , ta , tb , id; n = read() , m = read(); for(i = 2 ; i <= n + 1 ; i ++ ) v[i] = read(); memset(tag , 0x3f , sizeof(tag)); ts[0] = 0xc0000000; build(1 , n + 2 , 0); root = (n + 3) >> 1; for(i = n + 3 ; i <= 600005 ; i ++ ) q.push(i); while(m -- ) { scanf("%s" , str); switch(str[2]) { case ‘S‘: { p = read() , t = read(); for(i = 1 ; i <= t ; i ++ ) { ta = find(root , p + i); splay(root , ta); tb = find(root , p + i + 1); splay(c[1][root] , tb); x = read(); id = q.front() , q.pop(); v[id] = x; fa[id] = c[1][root]; c[0][c[1][root]] = id; pushup(c[0][c[1][root]]); pushup(c[1][root]); pushup(root); } break; } case ‘L‘: { p = read() , t = read(); ta = find(root , p); splay(root , ta); tb = find(root , p + t + 1); splay(c[1][root] , tb); cls(c[0][c[1][root]]); c[0][c[1][root]] = 0; pushup(c[1][root]); pushup(root); break; } case ‘K‘: { p = read() , t = read() , x = read(); update(p + 1 , p + t , x); break; } case ‘V‘: { p = read() , t = read(); rever(p + 1 , p + t); break; } case ‘T‘: { p = read() , t = read(); ta = find(root , p); splay(root , ta); tb = find(root , p + t + 1); splay(c[1][root] , tb); printf("%d\n" , sum[c[0][c[1][root]]]); break; } default: { ta = find(root , 1); splay(root , ta); tb = find(root , si[root]); splay(c[1][root] , tb); printf("%d\n" , ts[c[0][c[1][root]]]); } } } return 0; }
以上是关于bzoj1500[NOI2005]维修数列的主要内容,如果未能解决你的问题,请参考以下文章