Description
请写一个程序,要求维护一个数列,支持以下6种操作:(请注意,格式栏中的下划线‘ _ ’表示实际输入文件中的空格)
1. 插入 INSERT_posi_tot_c1_c2_…_ctot 在当前数列的第posi个数字后插入tot个数字:c1, c2, …, ctot;若在数列首插入,则posi为0
2. 删除 DELETE_posi_tot 从当前数列的第posi个数字开始连续删除tot个数字
3. 修改 MAKE-SAME_posi_tot_c 将当前数列的第posi个数字开始的连续tot个数字统一修改为c
4. 翻转 REVERSE_posi_tot 取出从当前数列的第posi个数字开始的tot个数字,翻转后放入原来的位置
5. 求和 GET-SUM_posi_tot 计算从当前数列开始的第posi个数字开始的tot个数字的和并输出
6. 求和最大的子列 MAX-SUM 求出当前数列中和最大的一段子列,并输出最大和
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
Data Constraint
你可以认为在任何时刻,数列中至少有1个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
50%的数据中,任何时刻数列中最多含有30 000个数;
100%的数据中,任何时刻数列中最多含有500 000个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
Hint
题目大意:
略。
题解:
据说这是一道splay的初级毕业题,也是NOI出过的最恶心的数据结构题之一。
查询有两种:求和 和 最大子区间和。
求和就不用说了。
最大子区间和我们需要维护3个值:
a.从区间左端点开始的最大和。
b.从区间右端点开始的最大和。
c.整个区间的子区间最大和。
转移a,b非常简单,c就考虑两个子树分别的子区间最大和 和 把两个区间合并起来的最大和,类似于线段树。
插入,删除很好维护。
区间翻转就把指针交换,再把a,b交换,c的值是不会变的。
对于区间赋值,我们需要记录子树的大小,这样就可以快速得到a,b,c三个的值。
如果有这么简单也不错.
坑点:
把翻转标记打在x点上,必须是已经把x的左右指针 和 a,b交换过,否则会出bug。
区间赋值的标记的NULL值不能为0,因为有可能把整个区间变成0.
Code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
const int Maxn = 1000005, INF = 1e8;
int root, n, m, fa[Maxn], t[Maxn][2], p[Maxn], d[Maxn];
struct node {
int z, sum, ms, ls, rs, lz1, lz2, siz;
}a[Maxn];
int read(int &x) {
char ch = ' '; for(; ch != '-' && (ch < '0' || ch > '9');) ch = getchar();
int f = 1; x = 0;
if(ch == '-') f = -1, ch = getchar();
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
return x *= f;
}
void update(int x) {
if(!x) return;
a[x].siz = a[t[x][0]].siz + a[t[x][1]].siz + 1;
a[x].sum = a[t[x][0]].sum + a[t[x][1]].sum + a[x].z;
a[x].ls = max(a[t[x][0]].ls, a[t[x][0]].sum + a[t[x][1]].ls + a[x].z);
a[x].ls = max(a[x].ls, a[t[x][0]].sum + a[x].z);
a[x].rs = max(a[t[x][1]].rs, a[t[x][1]].sum + a[t[x][0]].rs + a[x].z);
a[x].rs = max(a[x].rs, a[t[x][1]].sum + a[x].z);
a[x].ms = max(a[t[x][0]].ms, a[t[x][1]].ms);
a[x].ms = max(a[x].ms, a[t[x][0]].rs + a[t[x][1]].ls + a[x].z);
a[x].ms = max(a[x].ms ,a[t[x][0]].rs + a[x].z);
a[x].ms = max(a[x].ms, a[t[x][1]].ls + a[x].z);
a[x].ms = max(a[x].ms, a[x].z);
}
int lr(int x) {return t[fa[x]][1] == x;}
void chan1(int x) {
if(!x) return;
swap(t[x][0], t[x][1]);
swap(a[x].ls, a[x].rs);
a[x].lz1 ^= 1;
}
void chan2(int x, int y) {
if(!x) return;
a[x].z = y, a[x].sum = a[x].siz * y;
a[x].ms = a[x].ls = a[x].rs = (y > 0) ? (y * a[x].siz) : y;
a[x].lz2 = y;
}
void down(int x) {
if(!x) return;
if(a[x].lz1) chan1(t[x][0]), chan1(t[x][1]), a[x].lz1 = 0;
if(a[x].lz2 != INF) chan2(t[x][0], a[x].lz2), chan2(t[x][1], a[x].lz2), a[x].lz2 = INF;
}
void rotate(int x) {
int y = fa[x], k = lr(x);
t[y][k] = t[x][!k];
if(t[x][!k]) fa[t[x][!k]] = y;
fa[x] = fa[y];
if(fa[y]) t[fa[y]][lr(y)] = x;
t[x][!k] = y; fa[y] = x;
update(y);
}
void xc(int x) {
while(x) p[++ p[0]] = x, x = fa[x];
for(; p[0]; p[0] --) down(p[p[0]]);
}
void splay(int x, int y) {
xc(x);
while(fa[x] != y) {
if(fa[fa[x]] != y)
if(lr(fa[x]) == lr(x)) rotate(fa[x]); else rotate(x);
rotate(x);
}
update(x);
}
int find(int x, int y) {
down(x);
if(a[t[x][0]].siz >= y) return find(t[x][0], y);
if(a[t[x][0]].siz + 1 == y) return x;
return find(t[x][1], y - a[t[x][0]].siz - 1);
}
void Init() {
fo(i, 1, 1000000) a[i].lz2 = INF;
read(n); read(m);
a[0].ms = a[0].ls = a[0].rs = a[1].z = a[n + 2].z = -INF;
a[1].siz = 1;
fo(i, 1, n) {
read(a[i + 1].z);
a[i + 1].sum = a[i + 1].ls = a[i + 1].rs = a[i + 1].ms = a[i + 1].z;
fa[i] = i + 1; t[i + 1][0] = i; update(i + 1);
}
fa[n + 1] = n + 2; t[n + 2][0] = n + 1; update(n + 2);
d[0] = 500000 - n;
fo(i, n + 2, n + d[0] + 1) d[i - n - 1] = i;
}
void back(int x) {
if(!x) return;
back(t[x][0]); back(t[x][1]);
d[++ d[0]] = x;
t[x][0] = t[x][1] = a[x].lz1 = fa[x] = 0; a[x].lz2 = INF;
}
void dg(int x) {
if(!x) return;
printf("%d %d %d\n", x, t[x][0], t[x][1]);
dg(t[x][0]); dg(t[x][1]);
}
void Work() {
root = n + 2;
fo(T, 1, m) {
char s[20]; scanf("%s", s);
int posi, tot, c;
if(s[0] == 'I') {
read(posi); read(tot);
int x = find(root, posi + 1), y = find(root, posi + 2);
splay(x, 0); splay(y, x);
int z = d[d[0] --];
read(a[z].z);
a[z].siz = 1;
a[z].sum = a[z].ms = a[z].ls = a[z].rs = a[z].z;
fa[z] = y; t[y][0] = z; update(y);
int last = z;
fo(i, 2, tot) {
z = d[d[0] --];
read(a[z].z);
a[z].siz = 1;
a[z].sum = a[z].ms = a[z].ls = a[z].rs = a[z].z;
fa[z] = last; t[last][1] = z; update(last); last = z;
}
splay(z, 0); root = z;
}
if(s[0] == 'D') {
read(posi); read(tot);
int xx = find(root, posi), yy = find(root, posi + tot + 1);
splay(xx, 0); splay(yy, xx); root = xx;
back(t[yy][0]), t[yy][0] = 0;
update(yy); update(xx);
}
if(s[0] == 'M' && s[2] == 'K') {
read(posi); read(tot); read(c);
int xx = find(root, posi), yy = find(root, posi + tot + 1);
splay(xx, 0); splay(yy, xx);
chan2(t[yy][0], c);
root = t[yy][0]; splay(root, 0);
}
if(s[0] == 'R') {
read(posi); read(tot);
int xx = find(root, posi), yy = find(root, posi + tot + 1);
splay(xx, 0); splay(yy, xx);
chan1(t[yy][0]);
root = t[yy][0]; splay(root, 0);
}
if(s[0] == 'G') {
read(posi); read(tot);
int xx = find(root, posi), yy = find(root, posi + tot + 1);
splay(xx, 0); splay(yy, xx); root = xx;
printf("%d\n", a[t[yy][0]].sum);
}
if(s[0] == 'M' && s[2] == 'X') {
printf("%d\n", a[root].ms);
}
}
}
int main() {
freopen("2413.in", "r", stdin);
freopen("2413.out", "w", stdout);
Init();
Work();
}