原题 P3372 想要做到区间修改和区间查询O(logN)复杂度 求指正 代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,m,w[N];
struct node{//代表一个节点
int l,r,sum,add;//代表左右端点和区间和
}tr[N*4];
//变量add代表“记账本”
//当区间修改时,如果x-y区间完全覆盖a-b区间
//先修改x-y区间的sum值,同时记在记账本上,然后返回
// 下次需要查询a-b区间时,再下发欠下的值
//此做法可使修改与查询的时间复杂度都控制到O(logn)
void pushup(int p){//向上更新
tr[p].sum=tr[p*2].sum+tr[p*2+1].sum;
}
void pushdown(int p){//向下更新
if(tr[p].add){
int num=tr[p].add*(tr[p*2].r-tr[p*2].l+1);
tr[p*2].sum+=num,tr[p*2+1].sum+=num;
tr[p*2].add+=tr[p].add,tr[p*2+1].add+=tr[p].add;
tr[p].add=0;
}
}
void build(int p,int l,int r){//建树
tr[p]={l,r,w[l],0};
if(l==r) return;//是叶子就返回
else{//不是就裂开
int m=(l+r)/2;
build(p*2,l,m);
build(p*2+1,m+1,r);
pushup(p);
}
}
void update(int p,int x,int y,int k){//x-y为节点位置,k为修改的值
if(tr[p].l>=x&&tr[p].r<=y){
tr[p].sum+=(tr[p].r-tr[p].l+1)*k;
tr[p].add+=k;
return;
}
else{
pushdown(p);
int m=(tr[p].l+tr[p].r)/2;
if(x<=m) update(p*2,x,y,k);
else update(p*2+1,x,y,k);
pushup(p);
}
}
int query(int p,int x,int y){//区间查询
if(x<=tr[p].l&&tr[p].r<=y) return tr[p].sum;
int m=(tr[p].l+tr[p].r)/2;//区间覆盖了当前节点则返回不覆盖就裂开
pushdown(p);
int sum=0;
if(x<=m) sum+=query(p*2,x,y);
else sum+=query(p*2+1,x,y);
return sum;
}
int main(){
ios::sync_with_stdio(false);
int a,x,y,k;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>w[i];
build(1,1,n);
while(m--){
cin>>a>>x>>y;
if(a==1){
cin>>k;
update(1,x,y,k);
}
else{
cout<<query(1,x,y)<<endl;
}
}
return 0;
}