我的想法是结点维护前缀和,并进行区间查询和更新,但是总是4,5,7三个点WA
#include <cstdio>
#include <algorithm>
#include <cstring>
#define long long long
#define lc(x) (x)*2
#define rc(x) (x)*2+1
const int M=100001;
using namespace std;
struct seg_tree {
long val,tag;
seg_tree():val(0),tag(0) {}
};
//线段树结点中保存前缀和
seg_tree node[M*4];
int n,a[M];
inline void push_down(int k,int l,int r) {
int child_len=(r-l+1)/2;
node[lc(k)].val+=(long)child_len*node[k].tag;
node[rc(k)].val+=(long)child_len*node[k].tag;
node[lc(k)].tag+=node[k].tag;
node[rc(k)].tag+=node[k].tag;
node[k].tag=0;
}
void update(int st,int end,int val,int k=1,int l=1,int r=n) {
if(l>end||r<st) return;
if(l>=st&&r<=end) {
node[k].val+=(long)val*(r-l+1);
node[k].tag+=(long)val;
return;
}
push_down(k,l,r);
int mid=(l+r)/2;
update(st,end,val,lc(k),l,mid);
update(st,end,val,rc(k),mid+1,r);
node[k].val=node[lc(k)].val+node[rc(k)].val;
}
long query(int st,int end,int k=1,int l=1,int r=n) {
if(l>end||r<st) return 0;
if(l>=st&&r<=end) {
return node[k].val;
}
push_down(k,l,r);
int mid=(l+r)/2;
long L=query(st,end,lc(k),l,mid);
long R=query(st,end,rc(k),mid+1,r);
return L+R;
}
int main(){
int m,i;
long sum=0;
static char q[7];
scanf("%d%d",&n,&m);
//将n扩大为2的倍数方便求解
int t=n;
for(i=0; (1<<i)<n; i++);
n=(1<<i);
for(int i=1; i<=t; i++) {
scanf("%d",&a[i]);
sum+=(long)a[i];
update(i,i,sum);
}
for(int i=1; i<=n*2; i++) node[i].tag=0;
while(m--) {
int i;
scanf("%s%d",q,&i);
if(strcmp(q,"Modify")==0) {
int x;
scanf("%d",&x);
update(i,n,x-a[i]);
a[i]=x;
}
else printf("%lld\n",query(1,i));
}
return 0;
}