描述
给一个长为N的数列,有M次操作,每次操作是以下两种之一:
(1)修改数列中的一个数
(2)求某次操作后连续一段的和
输入
第一行两个正整数N和M。
第二行N的整数表示这个数列。
接下来M行,每行开头是一个字符,若该字符为’M’,则表示一个修改操作,接下来两个整数x和y,表示把x位置的数修改为y;若该字符为’Q’,则表示一个询问操作,接下来三个整数x、y、z,表示求数列中[x,y]这段区间在第z次操作后的和。
输出
对每一个询问操作单独输出一行,表示答案。
样例输入
5 4
1 2 3 4 5
Q 2 3 0
M 3 5
Q 2 3 2
Q 1 3 1
样例输出
5
7
6
#include <cstdio>
#include <iostream>
using namespace std;
const int N=1e5+7;
struct Node{
int l, r, ls, rs, sum;
}tree[N*20];
int rt[N], cnt;
void pushup( int nd ){
tree[nd].sum=tree[tree[nd].ls].sum+tree[tree[nd].rs].sum;
}
void build( int &nd, int l, int r ){
nd=++cnt;
tree[nd].l=l, tree[nd].r=r;
if(l==r) {
scanf("%d", &tree[nd].sum );
return;
}
int mid=(l+r)>>1;
build( tree[nd].ls, l, mid );
build( tree[nd].rs, mid+1, r );
pushup(nd);
}
void modify(int pre, int &nd, int p, int val ){
nd=++cnt;
tree[nd]=tree[pre];
if( tree[nd].l==tree[nd].r ){
tree[nd].sum=val;
return;
}
int mid=(tree[nd].l+tree[nd].r)>>1;
if( mid>=p ) modify( tree[pre].ls, tree[nd].ls, p, val );
else modify( tree[pre].rs, tree[nd].rs, p, val );
pushup(nd);
}
void update( int pre, int &nd){
nd=++cnt;
tree[nd]=tree[pre];
}
int query( int nd, int l, int r ){
if( l<=tree[nd].l&&tree[nd].r<=r ){
return tree[nd].sum;
}
int ret=0;
int mid=(tree[nd].l+tree[nd].r)>>1;
if( mid>=l ) ret+=query( tree[nd].ls, l, r );
if( mid<r ) ret+=query( tree[nd].rs, l, r );
return ret;
}
int main(){
int n, m;
scanf("%d%d", &n, &m );
cnt=0;
build( rt[0], 1, n );
for ( int i=1; i<=m; i++ ){
char ch[5];
int x, y, z;
scanf("%s", ch );
if( ch[0]=='M' ){
scanf("%d%d", &x, &y );
modify( rt[i-1], rt[i], x, y );
}else {
scanf("%d%d%d", &x, &y, &z );
printf("%d\n", query(rt[z], x, y) );
update( rt[i-1], rt[i] );
}
}
return 0;
}