线段树1
用到线段树基础知识
#include<bits/stdc++.h>
using namespace std;
// 线段树我默认每个数组下标都是从1开始的
void build(const vector<long long>& nums,vector<long long>& d,int s,int t,int p);
long long getSum(vector<long long>& d,vector<long long>& b,int l,int r,int s,int t,int p);
void update_plus(vector<long long>& d,vector<long long>& b,int l,int r,int s,int t,int p,long long c);
int main()
{
int n,m,type,l,r;
long long k;
cin >> n >> m;
vector<long long> nums(n+1), d(4*n+1), b(4*n+1, 0); // 修改这里
for(int i=1;i<=n;i++) cin>>nums[i];
build(nums,d,1,n,1);
while(m--)
{
cin >> type;
if(type==2)
{
cin >> l >> r;
cout << getSum(d,b,l,r,1,n,1) << '\n';
}
else if(type==1)
{
cin >> l >> r >> k;
update_plus(d,b,l,r,1,n,1,k);
}
}
return 0;
}
void build(const vector<long long>& nums,vector<long long>& d,int s,int t,int p)
{
if(s==t)
{
d[p] = nums[s];
return;
}
int m = s + ((t-s)>>1);
build(nums,d,s,m,2*p);
build(nums,d,m+1,t,2*p+1);
d[p] = d[2*p] + d[2*p+1];
}
long long getSum(vector<long long>& d,vector<long long>& b,int l,int r,int s,int t,int p)
{
if(l<=s && t<=r)
{
return d[p];
}
int m = s + ((t-s)>>1);
long long sum=0;
if (b[p] && s != t) //下传懒标记
{
d[p*2] += b[p]*(m-s+1);
d[p*2+1] += b[p]*(t-m);
b[p*2] += b[p];
b[p*2+1] += b[p];
b[p] = 0;
}
if(l<=m) sum += getSum(d,b,l,r,s,m,2*p);
if(r>m) sum += getSum(d,b,l,r,m+1,t,2*p+1); //等价于r>=m+1
return sum;
}
void update_plus(vector<long long>& d,vector<long long>& b,int l,int r,int s,int t,int p,long long c)
{
// 当前区间为修改区间的子集时直接修改当前节点的值,修改后标记
if (l <= s && t <= r) {
d[p] += (t - s + 1) * c, b[p] += c;
return;
}
int m = s + ((t - s) >> 1);
if (b[p] && s != t) //下放标记(不会有s==t的情况因为s==t的时候肯定是lr的子区间已经直接return了)
{
d[p * 2] += b[p] * (m - s + 1), d[p * 2 + 1] += b[p] * (t - m);
b[p * 2] += b[p], b[p * 2 + 1] += b[p];
b[p] = 0;
}
if (l <= m) update_plus(d, b, l, r, s, m, p * 2, c);
if (r > m) update_plus(d, b, l, r, m + 1, t, p * 2 + 1, c);
d[p] = d[p * 2] + d[p * 2 + 1];
}
这里用了懒惰区间标记。对有些当次不需要访问但是确实有变化的区间进行了标记,如果下次访问到了标记区间,则执行修改并下放标记。
nums,d,b分别代表原数组,区间数组((从二叉树顶部为1开始(结点p子树为2p,2p+1)),结点懒惰标记数组。
update与getSum都需要用到标记判断与下放,判断条件是b[p] && s != t。