BZOJ 1500 [NOI2005]维修数列 题解

这道题还是比较裸的, 就是有点难码, 感觉能错的地方都错了一遍... 这里就提一些注意事项吧:

感觉对Splay一些基本操作的理解不够,或者说,对于线段树的一些基本操作理解不够.在维护下传标记方面Splay和线段树是相通的.这是一些问题:

  • 标记在什么时候下传:更具定义,在需要往下走的时候下传,即寻找第k大的时候.其他时候…其实是没有必要的.
  • 修改标记的定义:和线段树一样,一个点的标记定义为它的子树应该要更改的部分,所以在修改一个值的同时,不仅要修改它的标记,还要将它本身的值修改.这东西最好写一个函数,至少在这道题写函数之后才对的,并且并不知道bug处在哪
  • Splay前的更新:即在Splay之前将根节点到这个点上的所有点都pushdown.虽然有些代码没有写,但感觉还是要写一写为好.不写可能会错?
  • 前缀,后缀最大值的包含与不包含的问题:考虑它能不能不选.例如这道题,不能不选,所以如果全是负数,最大值也不能是0.
  • 前,后哨兵问题:哨兵是肯定要有的,否则肯定会出bug.对于哨兵的值的问题…这种维护数列的问题一般是设成0吧…这样的话就不会影响原来的值了.如果会影响的话,那么对于输出值的问题就可以将整个区间split出来就好了.

这里贴上调了若干天的代码 >_< :

#include <bits/stdc++.h>
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
#define INF 0x3f3f3f3f
#define N 1000006
using namespace std;

inline void cmax(int& x, int y) {
    if (x < y) x = y;
}

inline int read() { int x; scanf("%d", &x); return x;}

int cnt = 0, root, fa[N], ch[N][2], val[N], sz[N], rpl[N], rev[N], sum[N], lft[N], rht[N], mxs[N];
int stk[N], top;

inline void update(int x) {
    sz[x] = sz[lc(x)] + sz[rc(x)] + 1;
    sum[x] = sum[lc(x)] + sum[rc(x)] + val[x];
    lft[x] = sum[lc(x)] + val[x];
    if (rc(x)) cmax(lft[x], lft[x] + lft[rc(x)]);
    if (lc(x)) cmax(lft[x], lft[lc(x)]);
    rht[x] = sum[rc(x)] + val[x];
    if (lc(x)) cmax(rht[x], rht[x] + rht[lc(x)]);
    if (rc(x)) cmax(rht[x], rht[rc(x)]);
    mxs[x] = max(0, rht[lc(x)]) + val[x] + max(0, lft[rc(x)]);
    if (lc(x)) cmax(mxs[x], mxs[lc(x)]);
    if (rc(x)) cmax(mxs[x], mxs[rc(x)]);
}

inline void rever(int x) {
    swap(lc(x), rc(x));
    swap(lft[x], rht[x]);
    rev[x] ^= 1;
}

inline void tagup(int x, int w) {
    rpl[x] = val[x] = w;
    sum[x] = lft[x] = rht[x] = mxs[x] = sz[x] * w;
    if (w < 0) lft[x] = rht[x] = mxs[x] = w;
}

inline void pushdown(int x) {
    if (rev[x]) {
        if (lc(x)) rever(lc(x));
        if (rc(x)) rever(rc(x));
        rev[x] = 0;
    }
    if (rpl[x] != INF) {
        if (lc(x)) tagup(lc(x), rpl[x]);
        if (rc(x)) tagup(rc(x), rpl[x]);
        rpl[x] = INF;
    }
}

void pushup(int x) {
    if (fa[x]) pushup(fa[x]);
    pushdown(x);
}

inline void rotate(int x) {
    int y = fa[x], z = fa[y], d = rc(y) == x;
    pushdown(y), pushdown(x);
    ch[y][d] = ch[x][!d], fa[ch[y][d]] = y;
    fa[y] = x, ch[x][!d] = y; fa[x] = z;
    if (z) ch[z][rc(z) == y] = x;
    update(y), update(x);
}

inline void splay(int x, int goal) {
    pushup(x);
    while (fa[x] != goal) {
        int y = fa[x], z = fa[y];
        if (z != goal) rotate((rc(y) == x) == (rc(z) == y) ? y : x);
        rotate(x);
    }
    if (!goal) root = x;
}

inline int Get() {
    return top ? stk[top--] : ++cnt;
}

int kth(int k) {
    int rt = root;
    while (rt) {
        pushdown(rt);
        if (sz[lc(rt)] >= k) rt = lc(rt);
        else if (sz[lc(rt)] + 1 == k) return rt;
        else k -= sz[lc(rt)] + 1, rt = rc(rt);
    }
}

inline void isrt() {
    int k = read(), tot = read();
    splay(kth(k + 2), 0), splay(kth(k + 1), root);
    int lst = lc(root);
    rc(lst) = Get();
    while (tot--) {
        fa[rc(lst)] = lst;
        lst = rc(lst);
        val[lst] = read();
        if (tot) rc(lst) = Get();
    }
    splay(lst, 0);
}

void recy(int rt) {
    if (lc(rt)) recy(lc(rt));
    if (rc(rt)) recy(rc(rt));
    sum[rt] = val[rt] = sz[rt] = lc(rt) = rc(rt) = fa[rt] = 0;
    rpl[rt] = INF, rev[rt] = lft[rt] = rht[rt] = mxs[rt] = 0;
    stk[++top] = rt;
}

void output(int x) {
    pushdown(x);
    if (lc(x)) output(lc(x));
    if (rc(x)) output(rc(x));
    update(x);
}


inline void dele() {
    int k = read(), tot = read(), x;
    splay(kth(k + tot + 1), 0), splay(kth(k), root);
    x = rc(lc(root));
    recy(x); rc(lc(root)) = 0;
    splay(lc(root), 0);
}

inline void mdfy() {
    int k = read(), tot = read(), c = read(), x;
    splay(kth(k + tot + 1), 0), splay(kth(k), root);
    x = rc(lc(root));
    tagup(x, c);
    splay(x, 0);
}

inline void reve() {
    int k = read(), tot = read(), x, y = kth(k), z = kth(k + tot + 1);
    splay(z, 0), splay(y, root);
    x = rc(lc(root));
    rever(x);
    splay(x, 0);
}

inline int gtsum() {
    int k = read(), tot = read(), x, y = kth(k), z = kth(k + tot + 1);
    splay(z, 0), splay(y, root);
    x = rc(lc(root));
    return sum[x];
}

void getupdate(int x) {
    pushdown(x);
    if (lc(x)) getupdate(lc(x));
    if (rc(x)) getupdate(rc(x));
    update(x);
}

inline int mxsum() {
    splay(1, 0), splay(kth(sz[root]), 1);
    return mxs[lc(rc(root))];
}

int main() {
    memset(rpl, 0x3f, sizeof rpl);
    int n, m;
    n = read(), m = read();
    root = 1;
    rc(1) = 2;
    for (int i = 2; i <= n + 1; ++i) {
        val[i] = read();
        fa[i] = i - 1;
        rc(i) = i + 1;
        update(i);
    }
    fa[cnt = n + 2] = n + 1;
    splay(n + 2, root);
    getupdate(root);
    char op[20];
    while (m--) {
        scanf("%s", op);
        if (*op == 'I') isrt();
        if (*op == 'D') dele();
        if (*op == 'M' && *(op + 2) == 'K') mdfy();
        if (*op == 'R') reve();
        if (*op == 'G') printf("%d\n", gtsum());
        if (*op == 'M' && *(op + 2) == 'X') printf("%d\n", mxsum());
    }
    return 0;
}

posted @ 2019-06-10 17:20  Jerx2y  阅读(101)  评论(0编辑  收藏  举报