[平衡树刷题] 模板 P2042 [NOI2005] 维护数列

思路

很板的题,但是很有必要写。

对于最大子列和,用区间合并的思想求;

对于区间翻转,用平衡树反转的思想求;

对于插入区间,分裂后硬插即可,但注意不要裂成俩之后再调用原始的插入,因为裂开之后root变了,插入操作是错的。不如直接建一棵新的平衡树插点,然后在裂开合并三段即可。

注意下放标记的顺序。

好题!

**#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;

const int N = 5e5 + 10, INF = 1e9;

namespace FHQ {
    struct Info {
        int sum, pres, sufs, maxs;
        inline void init(int x, int sz) {
            sum = x * sz, pres = sufs = maxs = x < 0 ? x : sum;
        }
        inline void set(int x) { sum = pres = sufs = maxs = x; }
        inline void clc() { sum = 0, pres = sufs = maxs = -INF; }
        friend Info operator+ (Info a, Info b) {
            return Info {
                a.sum + b.sum,
                max(a.pres, a.sum + b.pres),
                max(b.sufs, b.sum + a.sufs),
                max({a.maxs, b.maxs, a.sufs + b.pres})};
        }
    } tree[N];

    struct stk {
        int s[N], id;
        stk(): id(0) {}
        void push(int x) { s[++id] = x; }
        int top() { return s[id]; }
        void pop() { --id; }
        bool empty() { return id == 0; }
    } stk;
    
    int lc[N], rc[N], key[N], siz[N], val[N], chg[N];;
    bool lazy[N];
    int tot, root;

    std::mt19937 Rand(114514);

    inline void make_node(int &rt, int x) {
        if(!stk.empty()) {
            rt = stk.top(), stk.pop();
            tree[rt].set(x);
        } else {
            tree[rt = ++tot].set(x);
        }
        val[rt] = x, key[rt] = Rand(), siz[rt] = 1, chg[rt] = INF, lazy[rt] = false;
    }

    inline void push_up(int rt) {
        siz[rt] = siz[lc[rt]] + siz[rc[rt]] + 1;
        Info now; now.set(val[rt]);
        tree[rt] = tree[lc[rt]] + now + tree[rc[rt]];
        // cout << "# Merged Operation: " << "(" << lc[rt] << ", " << rc[rt] << "), sum => " << tree[rt].sum << endl; 
    }

    inline void push_down(int rt) {
        if(lazy[rt]) {
            if(lc[rt]) lazy[lc[rt]] ^= 1, swap(tree[lc[rt]].pres, tree[lc[rt]].sufs);
            if(rc[rt]) lazy[rc[rt]] ^= 1, swap(tree[rc[rt]].pres, tree[rc[rt]].sufs);
            swap(lc[rt], rc[rt]);
            lazy[rt] = false;
        }
        if(chg[rt] < INF) {
            // cout << "# PushDown Change Tag: Root = " << rt << ", val = " << chg[rt] << endl;
            if(lc[rt]) tree[lc[rt]].init(chg[rt], siz[lc[rt]]), val[lc[rt]] = chg[lc[rt]] = chg[rt];
            if(rc[rt]) tree[rc[rt]].init(chg[rt], siz[rc[rt]]), val[rc[rt]] = chg[rc[rt]] = chg[rt];
            chg[rt] = INF;
        }
    }

    void split(int rt, int x, int &u, int &v) {
        if(!rt) return u = v = 0, void();
        push_down(rt);
        if(x > siz[lc[rt]]) u = rt, split(rc[rt], x - siz[lc[rt]] - 1, rc[rt], v);
        else v = rt, split(lc[rt], x, u, lc[rt]);
        push_up(rt);
    }

    int merge(int u, int v) {
        if(!u || !v) return u + v;
        push_down(u), push_down(v);
        if(key[u] > key[v]) {
            rc[u] = merge(rc[u], v);
            return push_up(u), u;
        } else {
            lc[v] = merge(u, lc[v]);
            return push_up(v), v;
        }
    }
    
    void insert(int x) {
        int new_node; make_node(new_node, x);
        root = merge(root, new_node);
    }

    void clc(int x) {
        tree[x].clc(), val[x] = lc[x] = rc[x] = siz[x] = key[x] = lazy[x] = 0, chg[x] = INF;
        stk.push(x);
    }
    
    void del(int x) {
        if(!x) return;
        del(lc[x]), del(rc[x]), clc(x);
    }
}

using FHQ::root;
using FHQ::stk;

inline int get_opid(string op) {
    if(op[0] == 'I') return 1;
    else if(op[0] == 'D') return 2;
    else if(op[0] == 'M' && op[2] == 'K') return 3;
    else if(op[0] == 'R') return 4;
    else if(op[0] == 'G') return 5;
    else if(op[0] == 'M' && op[2] == 'X') return 6;
    return 0;
}

inline void solve() {
    FHQ::tree[0].clc();
    int n, m; cin >> n >> m;
    for(int i = 1; i <= n; i++) {
        int x; cin >> x;
        FHQ::insert(x);
    }   
    for(int c = 1; c <= m; c++) {
        
        string op; cin >> op;
        int ops = get_opid(op);
        if(ops == 1) {
            int posi, tot; cin >> posi >> tot;
            int nrt = 0; 
            for(int i = 1; i <= tot; i++) {
                int v = 0; cin >> v;
                int nd; FHQ::make_node(nd, v);
                nrt = FHQ::merge(nrt, nd);
            }
            int spl, spr;
            FHQ::split(root, posi, spl, spr);
            root = FHQ::merge(FHQ::merge(spl, nrt), spr);
            
        } else if(ops == 2) {
            int posi, tot; cin >> posi >> tot;
            int spl, spm, spr;
            FHQ::split(root, posi + tot - 1, spl, spr);
            FHQ::split(spl, posi - 1, spl, spm);
            FHQ::del(spm);
            root = FHQ::merge(spl, spr);
            
        } else if(ops == 3) {
            int posi, tot, chg; cin >> posi >> tot >> chg;
            int spl, spm, spr;
            FHQ::split(root, posi + tot - 1, spl, spr);
            FHQ::split(spl, posi - 1, spl, spm);
            FHQ::chg[spm] = FHQ::val[spm] = chg, FHQ::tree[spm].init(chg, FHQ::siz[spm]);            
            root = FHQ::merge(FHQ::merge(spl, spm), spr);
            // cout << "Test MID trans >>> " ;
            // FHQ::print_mid(root); cout << endl;
            // cout << "Test MID tags >>> " ;
            // FHQ::print_mid_chg(root); cout << endl;
        } else if(ops == 4) {
            int posi, tot; cin >> posi >> tot;
            int spl, spm, spr; 
            FHQ::split(root, posi + tot - 1, spl, spr);
            FHQ::split(spl, posi - 1, spl, spm);
            FHQ::lazy[spm] ^= 1;
            
            root = FHQ::merge(FHQ::merge(spl, spm), spr);
        } else if(ops == 5) {
            int posi, tot; cin >> posi >> tot;
            int spl, spm, spr; 
            FHQ::split(root, posi + tot - 1, spl, spr);
            FHQ::split(spl, posi - 1, spl, spm);
            cout << FHQ::tree[spm].sum << endl;
            root = FHQ::merge(FHQ::merge(spl, spm), spr);
        } else if(ops == 6) {
            cout << FHQ::tree[root].maxs << endl;
        }
    }

}

signed main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HeartFireY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值