Description

请写一个程序, 要求维护一个数列, 支持以下 \(6\) 种操作:

操作编号 输入文件中的格式 说明
1. 插入 INSERT posi tot c1 c2 ... ctot 在当前数列的第 \({pos}_i\) 个数字后插入 \(tot\) 个数字:\(c_1, c_2, \ldots, c_{tot}\); 若在数列首插入, 则 \({pos}_i\)\(0\)
2. 删除 DELETE posi tot 从当前数列的第 \({pos}_i\) 个数字开始连续删除 \(tot\) 个数字
3. 修改 MAKE-SAME posi tot c 将当前数列的第 \({pos}_i\) 个数字开始的连续 \(tot\) 个数字统一修改为 \(c\)
4. 翻转 REVERSE posi tot 取出从当前数列的第 \({pos}_i\) 个数字开始的 \(tot\) 个数字, 翻转后放入原来的位置
5. 求和 GET-SUM posi tot 计算从当前数列开始的第 \({pos}_i\) 个数字开始的 \(tot\) 个数字的和并输出
6. 求和最大的子列 MAX-SUM 求出当前数列中和最大的一段子列, 并输出最大和

Input

输入文件的第 \(1\) 行包含两个数 \(n\)\(m\),\(n\) 表示初始时数列中数的个数,\(m\) 表示 要进行的操作数目.

\(2\) 行包含 \(n\) 个数字, 描述初始时的数列.

以下 \(m\) 行, 每行一条命令, 格式参见问题描述中的表格.

Output

对于输入数据中的 GET-SUMMAX-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 Range

你可以认为在任何时刻, 数列中至少有 \(1\) 个数.

输入数据一定是正确的, 即指定位置的数在数列中一定存在.

50% 的数据中, 任何时刻数列中最多含有 \(30000\) 个数;

100% 的数据中, 任何时刻数列中最多含有 \(500000\) 个数.

100% 的数据中, 任何时刻数列中任何一个数字均在 \([-1000, 1000]\) 内.

100% 的数据中,\(m \leq 20000\), 插入的数字总数不超过 \(4000000\) 个, 输入文件大小不超过 \(20\) MB.

Explanation

遇到这种看起来很像 SuperMemo 的题目就应该果断 Splay......

但是如果内存只有这么一点那么一定要垃圾回收, 毕竟开的点和删的点都会很多但是如果不 回收就会爆炸 QwQ

吐槽: 结果写了一遍带上垃圾回收无限 RE, 终于修好 GC 模块以后又开始无限 TLE...... 最终 在 Miloris 大神的指引下选择了用 NOI 的官方数据测评, 结果一个 AC 三个 TLE 两个 WA 剩下全是 RE......

于是开始了一个星期的紧张调试, 感觉自己突然变成了 Splayed By Trees

终于有一天把程序调出来了...... 首先 interval 就没写对, 合并好像有点问题; 其次 find 函数会莫名崩溃, 主要原因是没有在向下 traverse 的时候发 lazy; 再然后就是 MAX-SUM 本来是不应该写那么麻烦的, 直接询问 root 的大小就行了; 最后应该把两个端点的 val 值设成 \(-\infty\) 才对, 不然分分钟 WA.

所以说这锅并不该垃圾回收背......

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cstring>

#define rep(_var,_begin,_end) for(int _var=_begin;_var<=_end;_var++)
#define range(_begin,_end) rep(_,_begin,_end)
#define max_3(__x,__y,__z) max(max(__x,__y),__z)
using namespace std;
typedef long long lli;
const int maxn = 500100;
const lli infinit = 0x3f3f3f3f;

class SplayTree
{
public:
    int arr_i[maxn][6];
    #define ch(_x,_y) arr_i[_x][_y]
    #define lc(_x) arr_i[_x][0]
    #define rc(_x) arr_i[_x][1]
    #define par(_x) arr_i[_x][2]
    #define size(_x) arr_i[_x][3]
    #define lazymod(_x) arr_i[_x][4]
    #define lazyrev(_x) arr_i[_x][5]
    lli arr_l[maxn][6];
    #define val(_x) arr_l[_x][0]
    #define sum(_x) arr_l[_x][1]
    #define lmx(_x) arr_l[_x][2]
    #define mmx(_x) arr_l[_x][3]
    #define rmx(_x) arr_l[_x][4]
    #define lazyset(_x) arr_l[_x][5]
    int n, ncnt, root;
    queue<int> npool;
    int make_node(void)
    {
        int p = 0;
        if (!npool.empty()) {
            p = npool.front();
            npool.pop();
        } else {
            p = ++ncnt;
        }
        lc(p) = rc(p) = par(p) = 0;
        size(p) = 1;
        lazymod(p) = lazyrev(p) = false;
        val(p) = sum(p) = lmx(p) = mmx(p) = rmx(p) = 0ll;
        lazyset(p) = 0ll;
        return p;
    }
    void destroy_node(int p)
    {
        npool.push(p);
        return ;
    }
    void mark_mod(int p, lli v)
    {
        lazymod(p) = true;
        lazyset(p) = v;
        val(p) = v;
        sum(p) = size(p) * val(p);
        if (val(p) >= 0) {
            lmx(p) = mmx(p) = rmx(p) = sum(p);
        } else {
            lmx(p) = rmx(p) = 0;
            mmx(p) = val(p);
        }
        return ;
    }
    void mark_rev(int p)
    {
        lazyrev(p) ^= 1;
        swap(lc(p), rc(p));
        swap(lmx(p), rmx(p));
        return ;
    }
    void update_lazy(int p)
    {
        size(p) = size(lc(p)) + 1 + size(rc(p));
        sum(p) = sum(lc(p)) + val(p) + sum(rc(p));
        lmx(p) = max(lmx(lc(p)), sum(lc(p)) + val(p) + lmx(rc(p)));
        mmx(p) = max_3(mmx(lc(p)), rmx(lc(p)) + val(p) + lmx(rc(p)), mmx(rc(p)));
        rmx(p) = max(rmx(lc(p)) + val(p) + sum(rc(p)), rmx(rc(p)));
        return ;
    }
    void dispatch_lazy(int p)
    {
        if (lazymod(p)) {
            range(0, 1) if (ch(p, _))
                mark_mod(ch(p, _), val(p));
            lazymod(p) = lazyrev(p) = false;
        }
        if (lazyrev(p)) {
            range(0, 1) if (ch(p, _))
                mark_rev(ch(p, _));
            lazyrev(p) = false;
        }
        return ;
    }
    void rotate(int p)
    {
        int q = par(p), g = par(q);
        int x = p == rc(q), y = q == rc(g);
        dispatch_lazy(q);
        dispatch_lazy(p);
        ch(q, x) = ch(p, !x); if (ch(q, x)) par(ch(q, x)) = q;
        ch(p, !x) = q; par(q) = p;
        if (g) ch(g, y) = p; par(p) = g;
        update_lazy(q);
        update_lazy(p);
        return ;
    }
    void splay(int p, int t = 0)
    {
        for (int q = 0; (q = par(p)) && q != t; rotate(p))
            if (par(q) && par(q) != t)
                rotate((p == lc(q)) == (q == lc(par(q))) ? q : p);
        if (t == 0) root = p;
        return ;
    }
    int find(int x)
    {
        int p = root;
        while (p) {
            dispatch_lazy(p);
            if (x <= size(lc(p))) {
                p = lc(p);
                continue;
            } x -= size(lc(p));
            if (x <= 1) {
                return p;
            } x -= 1;
            p = rc(p);
        }
        return p;
    }
    int build_tree(int l, int r, lli arr[])
    {
        if (l > r) return 0;
        // So unless it's null node, we assume it's correct
        int p = make_node();
        int mid = (l + r) >> 1;
        val(p) = arr[mid];
        lc(p) = build_tree(l, mid - 1, arr);
        rc(p) = build_tree(mid + 1, r, arr);
        range(0, 1) if (ch(p, _)) par(ch(p, _)) = p;
        update_lazy(p);
        return p;
    }
    void insert(int pos, int n, lli arr[])
    {
        int lp = find(pos + 1), rp = find(pos + 2);
        splay(lp, 0);
        splay(rp, root);
        int np = build_tree(1, n, arr);
        lc(rp) = np;
        par(np) = rp;
        splay(np, 0);
        this->n += n;
        return ;
    }
    void remove(int l, int r)
    {
        int lp = find(l), rp = find(r + 2);
        splay(lp, 0);
        splay(rp, root);
        // Recycling subtree
        queue<int> que;
        que.push(lc(rp));
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            range(0, 1) if (ch(p, _))
                que.push(ch(p, _));
            destroy_node(p);
        }
        // Disconnecting
        lc(rp) = 0;
        splay(rp, 0);
        this->n -= r - l + 1;
        return ;
    }
    void change(int l, int r, lli val)
    {
        int lp = find(l), rp = find(r + 2);
        splay(lp, 0);
        splay(rp, root);
        mark_mod(lc(rp), val);
        splay(lc(rp), 0);
        return ;
    }
    void reverse(int l, int r)
    {
        int lp = find(l), rp = find(r + 2);
        splay(lp, 0);
        splay(rp, root);
        mark_rev(lc(rp));
        splay(lc(rp), 0);
        return ;
    }
    lli get_sum(int l, int r)
    {
        int lp = find(l), rp = find(r + 2);
        splay(lp, 0);
        splay(rp, root);
        lli res = sum(lc(rp));
        return res;
    }
    int get_max_sum(void)
    {
        return mmx(root);
    }
    void init(void)
    {
        this->n = 0;
        this->ncnt = 0;
        while (!npool.empty())
            npool.pop();
        this->root = make_node();
        rc(root) = make_node();
        par(rc(root)) = root;
        size(root) += 1;
        mmx(0) = val(root) = val(rc(root)) = -infinit;
        splay(rc(root), 0);
        return ;
    }
} st;

int n, m;
lli arr[maxn];
char str[64];

int main(int argc, char** argv)
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &arr[i]);
    st.init();
    st.insert(0, n, arr);
    for (int idx = 1; idx <= m; idx++) {
        scanf("%s", str);
        if (str[0] == 'I') {
            int pos, tot; scanf("%d%d", &pos, &tot);
            for (int i = 1; i <= tot; i++)
                scanf("%lld", &arr[i]);
            st.insert(pos, tot, arr);
        } else if (str[0] == 'D') {
            int pos, tot; scanf("%d%d", &pos, &tot);
            st.remove(pos, pos + tot - 1);
        } else if (str[0] == 'M' && str[2] == 'K') {
            int pos, tot, v; scanf("%d%d%d", &pos, &tot, &v);
            st.change(pos, pos + tot - 1, v);
        } else if (str[0] == 'R') {
            int pos, tot; scanf("%d%d", &pos, &tot);
            st.reverse(pos, pos + tot - 1);
        } else if (str[0] == 'G') {
            int pos, tot; scanf("%d%d", &pos, &tot);
            lli res = st.get_sum(pos, pos + tot - 1);
            printf("%lld\n", res);
        } else if (str[0] == 'M' && str[2] == 'X') {
            lli res = st.get_max_sum();
            printf("%lld\n", res);
        }
    }
    return 0;
}