线段树(SegmentTree)
线段树
作用: 支持对一个数组进行高效的查询和修改
时间复杂度: 建树O(n) 查询和修改O(logn)
代码:
#include<iostream>
using namespace std;
#define int long long
#define endl '\n'
// SegmentTree templete
const int N = 1000010;
int arr[N];
int sum[N << 2];
int add[N << 2];
//汇总左右孩子的和
void up(int i){
sum[i] = sum[i << 1] + sum[i << 1 | 1];
}
//更新 sum 并添加懒信息
void lazy(int i,int v,int n){
sum[i] += v * n;
add[i] += v;
}
//下发懒信息并将自己的懒信息清零
void down(int i,int ln,int rn){
if(add[i]!=0){
lazy(i << 1,add[i],ln);
lazy(i << 1 | 1,add[i],rn);
add[i] = 0;
}
}
//建树
void build(int l,int r,int i){
if(l == r){
sum[i] = arr[l];
}
else{
int mid = (l + r) >> 1;
build(l,mid,i << 1);
build(mid+1,r,i << 1 | 1);
up(i);
}
add[i] = 0;
}
//将jobl ~ jobr 中的每个数都添加 v,从 l r i 位置开始,初始时为 1, n , 1;
void Add(int jobl,int jobr,int v,int l,int r,int i){
//全包含直接lazy
if(l >= jobl && r <= jobr){
lazy(i,v,r - l + 1);
}
else {
int mid = (l+r) >> 1;
//往下一层找,先将懒信息下发
down(i,mid - l + 1,r - mid);
//左边包含
if(mid >= jobl){
Add(jobl,jobr,v,l,mid,i << 1);
}
//右边包含
if(mid < jobr){
Add(jobl,jobr,v,mid+1,r,i << 1 | 1);
}
//汇总信息
up(i);
}
}
int query(int jobl,int jobr,int l,int r,int i){
//全包直接返回和
if(l >= jobl && r <= jobr){
return sum[i];
}
else {
int mid = (l + r) >> 1;
//先下发懒信息
down(i,mid - l + 1,r - mid);
int ans = 0;
if(mid >= jobl){
ans += query(jobl,jobr,l,mid,i << 1);
}
if(mid < jobr){
ans += query(jobl,jobr,mid+1,r,i<<1 | 1);
}
return ans;
}
}
signed main(){
int n,q;
cin >> n >> q;
for(int i = 1;i<=n;i++)cin >> arr[i];
build(1,n,1);
while(q--){
int op;
cin >> op;
if(op == 1){
int jobl,jobr,v;
cin >> jobl >> jobr >> v;
Add(jobl,jobr,v,1,n,1);
}
else if(op == 2){
int jobl,jobr;
cin >> jobl >> jobr;
cout << query(jobl,jobr,1,n,1) << endl;
}
}
return 0;
}
浙公网安备 33010602011771号