主席樹 區間更新。 好題目;
又學會了一種方法。。 這種方法可以不寫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;
}