BZOJ1500: [NOI2005]维修数列

妈呀,写的我心态崩了,注意以下几点:

1.标记下放时应该立即更新子节点,才能pushup更新当前结点(此时实际上在当前结点的标记已经使用过了)。

2.最好类似线段树的建树方法,否则容易RE。

3.写个回收。

4.我这splay写的是菜出狗屎了,在rotate里面pushdown,妈呀,就是因为没注意第一点,而且常数贼大,虽然可以过。

5.其他就是加两个结点0,n+1,好处理就行了。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstring>
#include <string>
#include <bitset>
#include <stack>
#include <set>
#include <map>
#include <list>
#include <assert.h>
using namespace std;
#define e exp(1.0)
typedef long long ll;
#define MAXN 500005
#define mod 100000007
#define INF 1000000000
#define fe(i,st,en) for(i = (st);i <= (en);++i)
#define fne(i,st,en) for(i = (st);i < (en);++i)
#define ri register int
#define db double
int n,b[MAXN];
struct Splay {
    int a[MAXN], sz[MAXN], s[MAXN], lazy[MAXN],rev[MAXN], son[MAXN][2],lma[MAXN],rma[MAXN], ma[MAXN], fa[MAXN], root;
    int sta[MAXN], coll[MAXN], coll_top, _sz;
    void pushup(int o) {//o后代的信息修改后调用
        s[o] = a[o], sz[o] = 1;
        s[o] += s[son[o][0]], sz[o] += sz[son[o][0]];
        s[o] += s[son[o][1]], sz[o] += sz[son[o][1]];
        lma[o] = max(0, max(s[son[o][0]] + a[o] + lma[son[o][1]], lma[son[o][0]]));//该点表示的的区间前缀最大和
        rma[o] = max(0, max(s[son[o][1]] + a[o] + rma[son[o][0]], rma[son[o][1]]));//该点表示的的区间后缀最大和
        ma[o] = max(lma[son[o][1]]+rma[son[o][0]]+a[o], max(ma[son[o][0]], ma[son[o][1]]));
    }
    int build(int o,int l,int r,int v) {
        if (l > r) return 0;
        int mid = (l + r) >> 1;
        o = newnode(o, v, b[mid]);
        build(o,l,mid-1,0);
        build(o, mid+1, r,1);
        pushup(o);
        return o;
    }
    void pushdown(int o) {//查找询问前调用
        if (rev[o]) {
            swap(son[o][0], son[o][1]);
            swap(lma[o], rma[o]);
            if (son[o][0]) rev[son[o][0]] ^= 1;
            if (son[o][1]) rev[son[o][1]] ^= 1;
            rev[o] = 0;
        }
        if (lazy[o] != -INF) {
            a[o] = lazy[o], s[o] = lazy[o] * sz[o], ma[o] = max(lazy[o], lazy[o] * sz[o]);//lazy为负则max为lazy[o],否则为lazy[o]*sz[o]
            if (lazy[o] < 0) lma[o] = rma[o] = 0;
            else lma[o] = rma[o] = ma[o];
            if (son[o][0]) lazy[son[o][0]] = lazy[o];
            if (son[o][1]) lazy[son[o][1]] = lazy[o];
            lazy[o] = -INF;
        }
    }
    void change(int o, int fo, int v) {
        son[fo][v] = o, fa[o] = fo;
    }
    int newnode(int fo,int v,int x) {
        int o;
        if (coll_top) o = coll[coll_top--];
        else o = _sz++;
        son[o][0] = son[o][1] = rev[o] = 0, sz[o] = 1, lazy[o] = -INF, ma[o] = s[o] = a[o] = x;
        if (x > 0) lma[o] = rma[o] = x;
        else lma[o] = rma[o] = 0;
        change(o, fo, v);
        return o;
    }
    int isright(int o, int fo) {
        return son[fo][1] == o;
    }
    void rotate(int o) {
        int f = fa[o], g = fa[f], v = isright(o, f);
        change(o, g, isright(f, g));
        if (root == f) root = o;
        change(son[o][v ^ 1], f, v);
        change(f, o, v ^ 1);
        pushdown(son[f][0]),pushdown(son[f][1]),pushup(f);
    }
    void splay(int o,int fo) {
        while (fa[o] != fo) {
            int f = fa[o], g = fa[f];
            if (g != fo) (isright(o, f) ^ isright(f, g)) ? rotate(o) : rotate(f);
            rotate(o);
        }
        pushdown(son[o][0]), pushdown(son[o][1]);
        pushup(o);
    }
    int findpos(int o,int pos) {//找pos对应结点的过程中,该结点o和root之间的结点均调用pushdown,可能这个结点,结果死循环!
         pushdown(o);//更新翻转标记
        if (sz[son[o][0]] + 1 == pos) return o;
        if (sz[son[o][0]] >= pos) return findpos(son[o][0], pos);
        return findpos(son[o][1], pos-sz[son[o][0]]-1);
    }
    void insert(int pos,int tot) {
        splay(findpos(root, pos + 1), 0);
        splay(findpos(root, pos + 2), root);//r翻转到root右儿子
        for (ri i = 1; i <= tot; ++i) scanf("%d", b + i);
        int o = build(0, 1, tot, 0);
        change(o, son[root][1], 0);
        pushup(son[root][1]);
        pushup(root);
        n += tot;
    }
    void del(int pos, int tot) {
        splay(findpos(root, pos),0);//l-1翻转到root
        splay(findpos(root, pos + tot + 1), root);//r+1翻转到root右儿子
        int o = son[son[root][1]][0], top = 0;
        sta[++top] = o;
        while (top) {
            int t = sta[top--];
            coll[++coll_top] = t;
            if (son[t][0]) sta[++top] = son[t][0];
            if (son[t][1]) sta[++top] = son[t][1];
        }
        son[son[root][1]][0] = 0;
        pushup(son[root][1]);
        pushup(root);
        n -= tot;
    }
    void update(int pos, int tot, int x) {
        splay(findpos(root, pos), 0);//l-1翻转到root
        splay(findpos(root, pos + tot + 1), root);//r+1翻转到root右儿子
        lazy[son[son[root][1]][0]] = x;
        pushdown(son[son[root][1]][0]);
        pushup(son[root][1]);
        pushup(root);//把lazy pushdown后更新root和root的右儿子信息
    }
    void reverse(int pos, int tot) {
        splay(findpos(root, pos), 0);//l-1翻转到root
        splay(findpos(root, pos + tot + 1), root);//r+1翻转到root右儿子
        rev[son[son[root][1]][0]] ^= 1;//翻转会改变祖辈信息
        pushdown(son[son[root][1]][0]);
        pushup(son[root][1]), pushup(root);//
    }
    int querySum(int pos, int tot) {
        splay(findpos(root, pos), 0);//l-1翻转到root
        splay(findpos(root, pos + tot + 1), root);//r+1翻转到root右儿子
        return s[son[son[root][1]][0]];
    }
    int queryMax() {
        splay(findpos(root, 1), 0);//l-1翻转到root
        splay(findpos(root, n+2), root);//r+1翻转到root右儿子
        return ma[son[son[root][1]][0]];
    }
}T;
int main() {
    //freopen("C:\\Users\\Administrator\\Desktop\\input.in", "r", stdin);
    //cout << (1 << 30) - 1 << endl;
    int m, x, p, k;
    char s[20];
    ri i;
    scanf("%d%d", &n, &m);
    fe(i, 1, n) scanf("%d", b+i);
    b[0] = b[n + 1] = T.ma[0] = T.a[0] = T.lazy[0] = -INF;
    T._sz = 1, T.root = 1;
    T.build(0,0,n+1,0);
    //cout <<"T._sz:"<< T._sz << endl;
    fe(i, 1, m) {
        scanf("%s", s);
        if (s[0] == 'I') {
            scanf("%d%d", &p, &k);
            T.insert(p, k);
        }
        else if (s[0] == 'D') scanf("%d%d", &p, &k),T.del(p, k);
        else if (s[0] == 'R') scanf("%d%d", &p, &k),T.reverse(p, k);
        else if (s[0] == 'G') scanf("%d%d", &p, &k),printf("%d\n", T.querySum(p, k));
        else if(s[2] == 'K') scanf("%d%d%d", &p, &k,&x),T.update(p, k, x);
        else printf("%d\n", T.queryMax());
    }
    return 0;
}

 

posted @ 2019-05-30 00:29  zhuiyicc  阅读(102)  评论(0编辑  收藏  举报