题解:BISHI126 【模板】动态区间和Ⅱ
题目链接
题目描述
支持两类操作:
- 1 l r x:区间加,把 [l,r] 内所有元素都加上 x
- 2 l r:区间和查询,输出
解题思路
两种典型实现均可:
- 线段树(区间加 + 区间和,懒标记);
- 区间版树状数组(两个 BIT 维护 range add & range sum,常数更小)。
下方分别给出代码。时间复杂度均为 。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
struct SegTree {
int n; vector<i64> sum, lz;
SegTree(int n=0): n(n) { sum.assign(4*n+4, 0); lz.assign(4*n+4, 0); }
void build(int idx, int l, int r, const vector<i64>& a){
if(l==r){ sum[idx]=a[l]; return; }
int mid=(l+r)>>1; build(idx<<1,l,mid,a); build(idx<<1|1,mid+1,r,a);
sum[idx]=sum[idx<<1]+sum[idx<<1|1];
}
void apply(int idx, int l, int r, i64 v){ sum[idx]+=v*(r-l+1); lz[idx]+=v; }
void push(int idx, int l, int r){ if(lz[idx]==0) return; int mid=(l+r)>>1; apply(idx<<1,l,mid,lz[idx]); apply(idx<<1|1,mid+1,r,lz[idx]); lz[idx]=0; }
void range_add(int idx, int l, int r, int ql, int qr, i64 v){
if(ql<=l && r<=qr){ apply(idx,l,r,v); return; }
push(idx,l,r); int mid=(l+r)>>1;
if(ql<=mid) range_add(idx<<1,l,mid,ql,qr,v);
if(qr>mid) range_add(idx<<1|1,mid+1,r,ql,qr,v);
sum[idx]=sum[idx<<1]+sum[idx<<1|1];
}
i64 range_sum(int idx, int l, int r, int ql, int qr){
if(ql<=l && r<=qr) return sum[idx];
push(idx,l,r); int mid=(l+r)>>1; i64 ans=0;
if(ql<=mid) ans+=range_sum(idx<<1,l,mid,ql,qr);
if(qr>mid) ans+=range_sum(idx<<1|1,mid+1,r,ql,qr);
return ans;
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m; if(!(cin>>n>>m)) return 0;
vector<i64> a(n+1); for(int i=1;i<=n;i++) cin>>a[i];
SegTree st(n); st.build(1,1,n,a);
while(m--){
int op; cin>>op;
if(op==1){ int l,r; i64 x; cin>>l>>r>>x; st.range_add(1,1,n,l,r,x); }
else{ int l,r; cin>>l>>r; cout<<st.range_sum(1,1,n,l,r)<<'\n'; }
}
return 0;
}
import java.io.*;
public class Main {
static class FastScanner {
private final InputStream in; private final byte[] buf = new byte[1<<16];
private int p=0,l=0; FastScanner(InputStream is){in=is;}
private int read() throws IOException { if(p>=l){ l=in.read(buf); p=0; if(l<=0) return -1; } return buf[p++]; }
int nextInt() throws IOException { int c; int s=1,x=0; do{c=read();}while(c<=32); if(c=='-'){s=-1;c=read();} while(c>32){ x=x*10+(c-'0'); c=read(); } return x*s; }
long nextLong() throws IOException { int c; long s=1,x=0; do{c=read();}while(c<=32); if(c=='-'){s=-1;c=read();} while(c>32){ x=x*10+(c-'0'); c=read(); } return x*s; }
}
static class SegTree {
int n; long[] sum, lz;
SegTree(int n){ this.n=n; sum=new long[4*n+4]; lz=new long[4*n+4]; }
void build(int idx,int l,int r,int[] a){ if(l==r){ sum[idx]=a[l]; return; } int m=(l+r)>>1; build(idx<<1,l,m,a); build(idx<<1|1,m+1,r,a); sum[idx]=sum[idx<<1]+sum[idx<<1|1]; }
void apply(int idx,int l,int r,long v){ sum[idx]+=v*(r-l+1); lz[idx]+=v; }
void push(int idx,int l,int r){ if(lz[idx]==0) return; int m=(l+r)>>1; apply(idx<<1,l,m,lz[idx]); apply(idx<<1|1,m+1,r,lz[idx]); lz[idx]=0; }
void add(int idx,int l,int r,int ql,int qr,long v){ if(ql<=l&&r<=qr){ apply(idx,l,r,v); return; } push(idx,l,r); int m=(l+r)>>1; if(ql<=m) add(idx<<1,l,m,ql,qr,v); if(qr>m) add(idx<<1|1,m+1,r,ql,qr,v); sum[idx]=sum[idx<<1]+sum[idx<<1|1]; }
long sumQ(int idx,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr) return sum[idx]; push(idx,l,r); int m=(l+r)>>1; long ans=0; if(ql<=m) ans+=sumQ(idx<<1,l,m,ql,qr); if(qr>m) ans+=sumQ(idx<<1|1,m+1,r,ql,qr); return ans; }
}
public static void main(String[] args) throws Exception {
FastScanner fs = new FastScanner(System.in);
int n = fs.nextInt();
int m = fs.nextInt();
int[] a = new int[n+1];
for(int i=1;i<=n;i++) a[i]=fs.nextInt();
SegTree st = new SegTree(n);
st.build(1,1,n,a);
StringBuilder out = new StringBuilder();
while(m-- > 0){
int op = fs.nextInt();
if(op==1){ int l=fs.nextInt(), r=fs.nextInt(); long x=fs.nextLong(); st.add(1,1,n,l,r,x); }
else { int l=fs.nextInt(), r=fs.nextInt(); out.append(st.sumQ(1,1,n,l,r)).append('\n'); }
}
System.out.print(out.toString());
}
}
import sys
data = sys.stdin.buffer.read().split()
it = iter(data)
n = int(next(it)); m = int(next(it))
a = [0]*(n+1)
for i in range(1, n+1):
a[i] = int(next(it))
# 区间版树状数组:两个 BIT 支持 range add & range sum
BIT1 = [0]*(n+1)
BIT2 = [0]*(n+1)
def _add(B, i, v):
while i <= n:
B[i] += v
i += i & -i
def _sum(B, i):
s = 0
while i > 0:
s += B[i]
i -= i & -i
return s
def range_add(l, r, v):
_add(BIT1, l, v); _add(BIT1, r+1, -v)
_add(BIT2, l, v*(l-1)); _add(BIT2, r+1, -v*r)
def prefix_sum(x):
return _sum(BIT1, x)*x - _sum(BIT2, x)
def range_sum(l, r):
if l > r:
l, r = r, l
return prefix_sum(r) - prefix_sum(l-1)
# 用单点加构建初始数组
for i in range(1, n+1):
range_add(i, i, a[i])
out_lines = []
for _ in range(m):
op = int(next(it))
if op == 1:
l = int(next(it)); r = int(next(it)); x = int(next(it))
range_add(l, r, x)
else:
l = int(next(it)); r = int(next(it))
out_lines.append(str(range_sum(l, r)))
sys.stdout.write('\n'.join(out_lines))
算法及复杂度
- 算法:线段树(懒标记)/ 两个树状数组(range add & range sum)
- 时间复杂度:
- 空间复杂度:
或