基于fhq-treap的区间问题

ezoj1852

要求写一个序列数据结构,支持区间加,区间翻转,区间最大值。

  • 线段树结构能否支持区间翻转?

线段树节点记录一个 l s , r s ls,rs ls,rs,打翻转标记。每次下传就交换左右孩子。

  • fhq-treap

以下标为关键字分裂, t r e a p treap treap中下标序列是始终不变的。理解成在下标序列上面挂的值在不停的变动。具体写法就是 s p l i t split split改成基于 s i z siz siz的。颇有“山不转水转”之感。

特别需要注意的是:需要额外记录每个点的值。 s p l i t split split m e r g e merge merge操作都要下放可能用到的标记。

跑得很慢。。。开 O 2 O2 O2就极快了。。

#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 5e4 + 5;
struct poi {
    int ls, rs, siz, rnd, rev;
    LL mx, val, tag;
};
struct Tree {
    poi tr[N];
    int rt = 0, tot = 0;
    inline void pushup(int k) {
        tr[k].siz = 1; tr[k].mx = tr[k].val;
        if ( tr[k].ls ) tr[k].siz += tr[ tr[k].ls ].siz, tr[k].mx = max(tr[k].mx, tr[ tr[k].ls ].mx);
        if ( tr[k].rs ) tr[k].siz += tr[ tr[k].rs ].siz, tr[k].mx = max(tr[k].mx, tr[ tr[k].rs ].mx);
    }
    inline void pushdown(int k) {
        if (!k) return ;
        if (tr[k].rev) {
            swap(tr[k].ls, tr[k].rs);
            if (tr[k].ls) tr[ tr[k].ls ].rev ^= 1;
            if (tr[k].rs) tr[ tr[k].rs ].rev ^= 1;
            tr[k].rev = 0;
        }
        if (tr[k].tag) {
            if (tr[k].ls) {
                tr[ tr[k].ls ].mx += tr[k].tag;
                tr[ tr[k].ls ].val += tr[k].tag;
                tr[ tr[k].ls ].tag += tr[k].tag;
            }
            if (tr[k].rs) {
                tr[ tr[k].rs ].mx += tr[k].tag;
                tr[ tr[k].rs ].val += tr[k].tag;
                tr[ tr[k].rs ].tag += tr[k].tag;
            }
            tr[k].tag = 0;
        }
    }
    inline void newnode(int &k, int v) {
        k = ++tot;
        tr[k].ls = tr[k].rs = 0;
        tr[k].siz = 1;
        tr[k].rnd = rand();
        tr[k].val = tr[k].mx = tr[k].rev = tr[k].tag = 0;
    }
    inline void split(int k, int &nls, int &nrs, int rk) {//所谓山不转水转
        if (!k) {
            nls = nrs = 0;
            return ;
        }
        if (tr[k].tag || tr[k].rev) pushdown(k);
        if (tr[ tr[k].ls ].siz >= rk){
            nrs = k;
            split(tr[k].ls, nls, tr[nrs].ls, rk);
        }
        else {
            nls = k;
            split(tr[k].rs, tr[nls].rs, nrs, rk - tr[ tr[k].ls ].siz - 1);
        }
        pushup(k);
    }
    inline void merge(int &k, int a, int b) {
        if ((!a) || (!b)) {
            k = a + b;
            return ;
        }
        if (tr[a].tag || tr[a].rev) pushdown(a);
        if (tr[b].tag || tr[b].rev) pushdown(b);
        if (tr[a].rnd < tr[b].rnd) {
            k = a;
            merge(tr[k].rs, tr[a].rs, b);
        }
        else {
            k = b;
            merge(tr[k].ls, a, tr[b].ls);
        }
        pushup(k);
    }
    inline void insert(int v) {
        int x = 0, y = 0, z = 0;
        split(rt, x, y, v);
        newnode(z, v);
        merge(x, x, z);
        merge(rt, x, y);
    }
    inline void update(int l, int r, int v) {
        int x = 0, y = 0, z = 0;
        split(rt, x, y, r);
        split(x, x, z, l - 1);
        tr[z].mx += v;
        tr[z].val += v;
        tr[z].tag += v;
        merge(x, x, z);
        merge(rt, x, y);
    }
    inline void rev(int l, int r) {
        int x = 0, y = 0, z = 0;
        split(rt, x, y, r);
        split(x, x, z, l - 1);
        tr[z].rev ^= 1;
        merge(x, x, z);
        merge(rt, x, y);
    }
    inline LL query(int l, int r) {
        int x = 0, y = 0, z = 0;
        split(rt, x, y, r);
        split(x, x, z, l - 1);
        LL res = tr[z].mx;
        merge(x, x, z);
        merge(rt, x, y);
        return res;
    }
    inline void debug(int cur) {
        if (tr[cur].ls ) debug(tr[cur].ls);
        printf("cur = %d  mx = %lld tag = %lld rev = %d ls = %d rs = %d\n", cur, tr[cur].mx, tr[cur].tag, tr[cur].rev, tr[cur].ls, tr[cur].rs);
        if (tr[cur].rs ) debug(tr[cur].rs);
    }
}T1;
int n, m;
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-')f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9'){ x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
int main() {
    //freopen("data.in", "r", stdin);
    //freopen("ezoj1852.out", "w", stdout);
    srand(6628347);
    n = read(); m = read();
    for (int i = 1; i <= n; ++i)T1.insert(i);
    //printf("rt = %d\n", T1.rt);
    for (int i = 1; i <= m; ++i) {
        int k, l, r, v;
        k = read();
        if (k == 1) {
            l = read(); r = read(); v = read();
            T1.update(l, r, v);
        }
        else
        if (k == 2) {
            l = read(); r = read();
            T1.rev(l, r);
        }
        else {
            l = read(); r = read();
            printf("%lld\n", T1.query(l, r));
        }
        //T1.debug(T1.rt); printf("\n");
     }
     return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值