模版_線段樹
阿新 • • 發佈:2018-06-02
stream return max 很多 const 我不 lse can amp
線段樹模版之——區間修改與求和
題目描述:
給出數的個數n以及操作數q:
對於q:
1 x y z 令區間[x, y]增加z
2 x y 求區間和
#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const int maxn=1e5+10;
int n, q;
LL a[maxn];
LL sum[maxn<<2], li[maxn<<2];
void _push_up(int rt) {
sum[rt]=sum[rt<<1]+sum[(rt<<1)|1];
}//向上更新,求區間和
void _setup(int l, int r, int rt) {
li[rt]=0;
if(l==r){
sum[rt]=a[l];
return ;
}
int mid=(l+r)>>1;
_setup(l, mid, rt<<1);
_setup(mid+1, r, (rt<<1)|1);
_push_up(rt);
}//建樹
void _push_down(int rt, int m) {
if(li[rt]) {
li[rt<<1]+=li[rt];
li[(rt<<1)|1]+=li[rt];
sum[rt<<1]+=li[rt]*(m-(m>>1));
sum[(rt<<1)|1]+=li[rt]*(m>>1);
li[rt]=0;
}
}//將li標記向下更新,傳遞給小區間
void _add(int x, int y, LL z, int l ,int r, int rt) {
if(x<=l && y>=r) {
li[rt]+=z;
sum[rt]+=z*(r-l+1);
return ;
}
_push_down(rt, r-l+1); //邊算邊更新,節省復雜度
int mid=(l+r)>>1;
if(x<=mid) _add(x, y, z, l, mid, rt<<1);
if(y>mid) _add(x, y, z, mid+1, r, (rt<<1)|1);
_push_up(rt);
}
LL _query(int x, int y, int l, int r, int rt) {
if(x<=l && y>=r) {
return sum[rt];
}
_push_down(rt, r-l+1); //求和時再順便更新一次
int mid=(l+r)>>1;
LL ans=0;
if(x<=mid) ans+=_query(x, y, l, mid, rt<<1);
if(y>mid) ans+=_query(x, y, mid+1, r, (rt<<1)|1); //‘夾‘區間
return ans;
}
int main() {
scanf("%d%d", &n, &q);
for(int i=1; i<=n; i++) {
scanf("%lld", a+i);
}
_setup(1, n, 1);
for(int i=0; i<q; i++) {
int ls;
scanf("%d", &ls);
if(ls==1) {
int x, y;
LL z;
scanf("%d%d%lld", &x, &y, &z);
_add(x, y, z, 1, n, 1);
} else if(ls==2) {
int x, y;
scanf("%d%d", &x, &y);
printf("%lld\n", _query(x, y, 1, n ,1));
}
}
return 0;
}
有很多代碼使用結構體實現線段樹,不過我不太習慣用結構體來實現,因為有時候看到一堆點很難受...
模版_線段樹