hdu 4348 主席树

主席树 区间更新。  好题目; 

又学会了一种方法。。  这种方法可以不写push_down;

还有就是。。 这里一定要提前建树, 不然空间复杂度为 (n+q)*logn 如果建树为n+ q*logn;

#include <bits/stdc++.h>
using namespace std;
int n,m;
const int MAXN = 4000010;
typedef long long ll;
ll sum[MAXN], lazy[MAXN];
int lc[MAXN], rc[MAXN],tot;
int root[MAXN];
void push_up(int i, int l, int r){
    sum[i] = sum[lc[i]] + sum[rc[i]] + (ll)(r - l+1) * lazy[i];
}
void build(int &i, int l, int r){
    i = ++tot;
    sum[i] = lazy[i] = lc[i] = rc[i] = 0;
    if(l == r){
        scanf("%lld", &sum[i]);
        return;
    }
    int mid = (l + r)>>1;
    build(lc[i], l, mid);
    build(rc[i], mid+1, r);
    push_up(i, l, r);
}
void insert(int pre, int &i, int l, int r, int L, int R, int val){
    i = ++tot;
    sum[i] = sum[pre], lc[i] = lc[pre], rc[i] = rc[pre], lazy[i] = lazy[pre];
    if( l == L && r == R){
        lazy[i] += val;
        sum[i] += (ll)val*(r - l + 1);
        return;
    }
    int mid = ( l + r ) >>1;
    if(L > mid) insert(rc[pre], rc[i], mid+1, r, L, R , val);
    else if(R <= mid) insert(lc[pre], lc[i], l, mid, L, R, val);
    else{
        insert(lc[pre], lc[i], l, mid, L, mid, val);
        insert(rc[pre], rc[i], mid+1, r, mid+1, R, val);
    }
    push_up(i, l, r);
}
ll query(int i, int l, int r, int L, int R, ll adv){
    if(l == L && r == R){
        return sum[i] + (ll)(adv)*(r - l + 1);
    }
    adv += lazy[i];
    int mid = (l + r) >> 1;
    if( L > mid ) return query(rc[i], mid+1, r, L, R, adv);
    else if( R<=mid) return query(lc[i], l, mid, L, R, adv);
    else{
        ll a = query(lc[i], l, mid, L, mid, adv);
        ll b = query(rc[i], mid+1, r, mid+1, R, adv);
        return a+b;
    }
}

int main(){
    while(cin>>n>>m){
        tot = 0;
        build(root[0], 1, n);
        char op[3];
        int x, y, z;
        int time = 0;
        while(m--){
            scanf("%s", op);
            if(op[0] == 'Q'){
                scanf("%d %d", &x, &y);
               printf("%I64d\n", query(root[time], 1, n, x, y, 0)); 
            }
            else if(op[0] == 'C'){
                scanf("%d %d %d", &x, &y, &z);
                time++;
                insert(root[time-1], root[time], 1, n, x, y, z);
            }
            else if(op[0] == 'H'){
                scanf("%d %d %d", &x, &y, &z);
                printf("%I64d\n", query(root[z], 1, n, x, y, 0));
            }
            else {
                scanf("%d", &time);
            }
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值