JZOJ2413 【NOI2005】维护数列

来源:互联网 发布:windows 2000 编辑:程序博客网 时间:2024/06/12 21:15

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();}
原创粉丝点击