写在前面
本菜鸡线段树学了好多遍
但是每次写还是得很长时间
有时有一个细节还要琢磨半天
所以为了今后避免以上事情发生
本菜鸡决定将这么长时间以来对线段树的认识汇总
好日后清算
模板
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5;
int add[N*4],tr[N*4],a[N];//
int n,y,x,op,m,k;
void build(int k,int l,int r){
if(l==r){
tr[k]=a[l];
return;
}
int mid=(l+r)/2;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
tr[k]=tr[2*k]+tr[2*k+1];
}
void Add(int k,int l,int r,int v){
tr[k]+=v*(r-l+1);
add[k]+=v;
}
void pushdown(int k,int l,int r){
if(!add[k]) return;//可写可不写
int mid=(l+r)/2;
Add(2*k,l,mid,add[k]);
Add(2*k+1,mid+1,r,add[k]);
add[k]=0;//标记下传完毕,本位值已正确
}
void longchange(int k,int l,int r,int x,int y,int v){
if(x<=l&&r<=y){
add[k]+=v;//这里为什么要写呢?
tr[k]+=v*(r-l+1);//观察下面就return
return;
}
pushdown(k,l,r);
int mid=(l+r)/2;
if(x<=mid) longchange(2*k,l,mid,x,y,v);
if(y>mid) longchange(2*k+1,mid+1,r,x,y,v);
tr[k]=tr[2*k]+tr[2*k+1];
}
int longquery(int k,int l,int r,int x,int y){
if(x<=l&&r<=y){
return tr[k];
}
pushdown(k,l,r);
int res=0,mid=(l+r)/2;
if(x<=mid) res+=longquery(2*k,l,mid,x,y);
if(y>mid) res+=longquery(2*k+1,mid+1,r,x,y);
return res;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build(1,1,n);
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&op,&x,&y);
if(op==1){
scanf("%lld",&k);
longchange(1,1,n,x,y,k);
}
if(op==2){
printf("%lld\n",longquery(1,1,n,x,y));
}
}
}
标签:int,线段,tr,mid,细节,理解,add,void
From: https://www.cnblogs.com/zcxnb/p/18362314