JZOJ2413 【NOI2005】维护数列

3 篇文章 0 订阅
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();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值