C79 线段树+标记永久化 区修+区查 Luogu P3372 线段树 1
视频链接:265 线段树+标记永久化 区修+区查 Luogu P3372 线段树 1_哔哩哔哩_bilibili
// 线段树+标记永久化 O(M*logN) #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define ls u<<1 #define rs u<<1|1 #define mid ((l+r)>>1) const int N=100005; typedef long long LL; int n,m,a[N]; LL sum[N*4],tag[N*4]; //区间和,永久标记 void build(int u,int l,int r){ //建树 sum[u]=a[l]; if(l==r) return; build(ls,l,mid); build(rs,mid+1,r); sum[u]=sum[ls]+sum[rs]; } void change(int u,int l,int r,int x,int y,LL k){ //区修 sum[u]+=(min(r,y)-max(x,l)+1)*k; //经过节点更新sum if(x<=l&&r<=y){tag[u]+=k;return;} //覆盖节点更新tag if(x<=mid) change(ls,l,mid,x,y,k); if(y>mid) change(rs,mid+1,r,x,y,k); } LL query(int u,int l,int r,int x,int y,LL s){ //区查 if(x<=l&&r<=y) return sum[u]+(min(r,y)-max(x,l)+1)*s; //覆盖即返回 LL res=0; s+=tag[u]; //累计标记,下传给儿子 if(x<=mid) res+=query(ls,l,mid,x,y,s); if(y>mid) res+=query(rs,mid+1,r,x,y,s); return res; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); int op,x,y; LL k; for(int i=1;i<=m;i++){ scanf("%d%d%d",&op,&x,&y); if(op==1) scanf("%lld",&k),change(1,1,n,x,y,k); else printf("%lld\n",query(1,1,n,x,y,0)); } }