线段树模板
//入门代码
#include<cstdio>
typedef long long ll;
using namespace std;
ll a[100005];
ll Seg[400005]={0},add[400005]={0};
int N,M;
inline void PushUp(int rt){Seg[rt]=Seg[rt<<1]+Seg[rt<<1|1];}
inline void Built(int l,int r,int rt){
if(l==r){
Seg[rt]=a[l];
return;
}
int m = (l+r)>>1;
Built(l,m,rt<<1);
Built(m+1,r,rt<<1|1);
PushUp(rt);
}
inline void Pushdown(int sizel,int sizer,int rt){
add[rt<<1]+=add[rt];add[rt<<1|1]+=add[rt];
Seg[rt<<1]+=add[rt]*sizel;Seg[rt<<1|1]+=add[rt]*sizer;
add[rt]=0;
}
inline void Update(int L,int R,ll C,int l,int r,int rt){
if(l>R||r<L)return;
if(L<=l&&R>=r){
add[rt]+=C;
Seg[rt]+=C*(r-l+1);
return;
}
int m = (r+l)>>1;
Pushdown((m-l+1),(r-m),rt);
if(L<=m)Update(L,R,C,l,m,rt<<1);
if(R>m)Update(L,R,C,m+1,r,rt<<1|1);
PushUp(rt);
}
inline ll query(int L,int R,int l,int r,int rt){
if(l>R||r<L)return 0;
if(L<=l&&R>=r){
return Seg[rt];
}
int m = (l+r)>>1;
Pushdown((m-l+1),(r-m),rt);
ll ans = 0;
if(L<=m)ans+=query(L,R,l,m,rt<<1);
if(R>m)ans+=query(L,R,m+1,r,rt<<1|1);
return ans;
}
int main(){
scanf("%d%d",&N,&M);
for(register int i=1;i<=N;i++)scanf("%d",&a[i]);
Built(1,N,1);
int point,l,r,x;
for(register int i=1;i<=M;i++){
scanf("%d",&point);
if(point==1){
scanf("%d%d%d",&l,&r,&x);
Update(l,r,x,1,N,1);
}
else{
scanf("%d%d",&l,&r);
printf("%lld\n",query(l,r,1,N,1));
}
}
return 0;
}
2018.12.7更
看到了一种叫标记永久化的写法,即不需要下传标记,每次直接计算对答案的贡献即可,据说在可持久化数据结构中会更方便。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100005
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mid ((l+r)>>1)
long long seg[MAXN<<2],tag[MAXN<<2];
int N,M;
inline void pushup(int rt,int l,int r) {
seg[rt] = seg[lson] + seg[rson] + tag[rt]*(r-l+1);
}
void Build(int rt,int l,int r) {
tag[rt] = 0;
if(l==r) {
scanf("%lld",&seg[rt]);
return;
}
Build(lson,l,mid);
Build(rson,mid+1,r);
pushup(rt,l,r);
}
void update(int L,int R,long long C,int rt,int l,int r) {
if(L<=l&&R>=r) {
tag[rt] += C;
seg[rt] += (r-l+1)*C;
return;
}
if(L>r||R<l) return;
if(L<=mid) update(L,R,C,lson,l,mid);
if(R>mid) update(L,R,C,rson,mid+1,r);
pushup(rt,l,r);
}
long long query(int L,int R,int rt,int l,int r) {
if(L<=l&&R>=r) return seg[rt];
if(L>r||R<l) return 0;
long long ans = tag[rt] * (std::min(r,R)-std::max(L,l)+1);
if(L<=mid) ans += query(L,R,lson,l,mid);
if(R>mid) ans += query(L,R,rson,mid+1,r);
return ans;
}
int main() {
scanf("%d%d",&N,&M);
Build(1,1,N);
int opt,l,r;
long long k;
for(int i=1;i<=M;++i) {
scanf("%d%d%d",&opt,&l,&r);
if(opt==1) {
scanf("%lld",&k);
update(l,r,k,1,1,N);
}
else printf("%lld\n",query(l,r,1,1,N));
}
return 0;
}
注意这里的pushup的改动,每次一定要计算上tag对本层的影响。