实际上线段树足够的空间 = n向上扩充到最近的2的某个次方)的两倍
举个例子:
假设数组长度为5,就需要5先扩充成8,8*2=16.线段树需要16个元素。如果数组元素为8,那么也需要16个元素。
#include <bits/stdc++.h>
#define maxn 100005
typedef long long ll;
using namespace std;
ll mod = 1e9 + 7;
ll a[maxn],add[maxn<<2];
ll tree[maxn<<2];
void bulid(ll l,ll r,ll o)
{
if(l == r)
{
tree[o] = a[l];
return ;
}
ll mid = l + ((r-l)>>1);
bulid(l,mid,o<<1);
bulid(mid+1,r,o<<1|1);
tree[o] = tree[o<<1] + tree[o<<1|1];
}
void pushdown(ll l,ll r,ll o)
{
if(add[o])
{
add[o<<1] += add[o];
add[o<<1|1] += add[o];
ll mid = l + ((r-l)>>1);
tree[o<<1] += add[o] * (mid - l + 1);
tree[o<<1|1] += add[o] * (r - mid);
add[o] = 0;
}
}
void update(ll l,ll r,ll ql,ll qr,ll key,ll o)
{
if(ql <= l && qr >= r)
{
add[o] += key;
tree[o] += key * (r - l + 1);
return ;
}
pushdown(l,r,o);
ll mid = l + ((r-l)>>1);
if(ql <= mid)update(l,mid,ql,qr,key,o<<1);
if(qr >= mid + 1)update(mid+1,r,ql,qr,key,o<<1|1);
tree[o] = tree[o<<1] + tree[o<<1|1];
}
ll query(ll l,ll r,ll ql,ll qr,ll o)
{
if(ql <= l && qr >= r)
{
return tree[o];
}
pushdown(l,r,o);
ll mid = l + ((r-l)>>1);
ll ans = 0;
if(ql <= mid)ans += query(l,mid,ql,qr,o<<1);
if(qr >= mid + 1)ans += query(mid+1,r,ql,qr,o<<1|1);
tree[o] = tree[o<<1] + tree[o<<1|1];
return ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
ll n,m;
cin >> n >> m;
for(int i = 1; i <= n ; i ++)
{
cin >> a[i];
}
bulid(1,n,1);
while(m--)
{
ll q,c,d,k;
cin >> q;
if(q == 1)
{
cin >> c >> d >> k;
update(1,n,c,d,k,1);
}
if(q == 2)
{
cin >> c >> d;
cout << query(1,n,c,d,1) << endl;
}
}
return 0;
}