主席树的区间修改

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1e18
#define pll pair<ll, ll>
#define vi vector<int>
#define vl vector<ll>
#define fi first
#define se second
#define lll __int128

const int N = 2e5 + 5; //节点上界
ll root[N], idx; //每个版本根节点, 编号器
struct XT {
    struct node{ll ln, rn, l, r, sum, add;}tr[N * 22]; //左儿子, 右儿子, 左边界, 右边界, 区间和, 懒标记
    void pushup(ll o){
        tr[o].sum = tr[tr[o].ln].sum + tr[tr[o].rn].sum;
    }
    void pushdown(ll o){
        if(tr[o].add){
            tr[++idx] = tr[tr[o].ln];
            tr[o].ln = idx;
            tr[++idx] = tr[tr[o].rn];
            tr[o].rn = idx;
            ll l = tr[o].ln, r = tr[o].rn;
            tr[l].sum += tr[o].add * (tr[l].r - tr[l].l + 1);
            tr[r].sum += tr[o].add * (tr[r].r - tr[r].l + 1);
            tr[l].add += tr[o].add;
            tr[r].add += tr[o].add;
            tr[o].add = 0;
        }
    }
    void build(ll &o, ll l, ll r){ //创建空树, 一般是0版本
        o = ++idx;
        tr[o].l = l;
        tr[o].r = r;
        if(l == r) return;
        ll m = (l + r) >> 1;
        build(tr[o].ln, l, m);
        build(tr[o].rn, m + 1, r);
    }
    void ins(ll p, ll &o, ll L, ll R, ll add){ //区间加 (前版本p, 当前版本o)
        o = ++idx;
        tr[o] = tr[p];
        ll l = tr[o].l, r = tr[o].r;
        if(L <= tr[o].l && R >= tr[o].r){
            tr[o].sum += add * (tr[o].r - tr[o].l + 1);
            tr[o].add += add;
            return;
        }
        ll m = (l + r) >> 1;
        pushdown(p);
        pushdown(o);
        if(L <= m)
            ins(tr[p].ln, tr[o].ln, L, R, add);
        if(R > m)
            ins(tr[p].rn, tr[o].rn, L, R, add);
        pushup(p);
        pushup(o);
    }
    ll query(ll p, ll o, ll L, ll R){ //版本作差查询区间和
        ll l = tr[o].l, r = tr[o].r;
        if(L <= l && R >= r)
            return tr[o].sum - tr[p].sum;
        pushdown(p);
        pushdown(o);
        ll m = (l + r) >> 1, res = 0;
        if(L <= m)
            res += query(tr[p].ln, tr[o].ln, L, R);
        if(R > m)
            res += query(tr[p].rn, tr[o].rn, L, R);
        pushup(p);
        pushup(o);
        return res;
    }
}xt;

int main() {
    return 0;
}

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值