其实在tzt版线段树的基础上稍微加一些东西就好了。我们不预先开点,每当需要用到一个点时,我们才开。空间复杂度可以优化到 m(查询)log n。
code(线段树1,其实这道题用动态开点没啥意义没啥意义,当作练习)
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include <stack>
#include<vector>
#define half (l+r)>>1;
using namespace std;
int n,m;
const int maxn=400000;
struct hzw
{
int sum;
int add;
int lc;
int rc;
}t[maxn];
int a[maxn],tot;
inline void update(int &s,int l,int r,int cl,int cr,int x)
{
if (!s) s=++tot;
t[s].sum+=(cr-cl+1)*x;
if (l==cl&&r==cr)
{
t[s].add+=x;
return ;
}
int mid=half;
if (cr<=mid) update(t[s].lc,l,mid,cl,cr,x);
else if (cl>mid) update(t[s].rc,mid+1,r,cl,cr,x);
else {
update(t[s].lc,l,mid,cl,mid,x);
update(t[s].rc,mid+1,r,mid+1,cr,x);
}
}
inline int query(int s,int l,int r,int cl,int cr,int cnt)
{
if (!s) return 0;
if (l==cl&&r==cr)
{
return cnt*(cr-cl+1)+t[s].sum;
}
int mid=half;
if (cr<=mid) return query(t[s].lc,l,mid,cl,cr,cnt+t[s].add);
else if (cl>mid) return query(t[s].rc,mid+1,r,cl,cr,cnt+t[s].add);
else {
return query(t[s].lc,l,mid,cl,mid,t[s].add+cnt)+query(t[s].rc,mid+1,r,mid+1,cr,cnt+t[s].add);
}
}
int main() {
int ans=0,cur;
tot++;
cin>>n>>m;
int root=1;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for (int i=1;i<=n;++i) update(root,1,n,i,i,a[i]);
for(int i=1,q,x,y;i<=m;i++)
{
scanf("%d%d%d",&q,&x,&y);
if(q==1)
{ scanf("%d",&cur);
update(root,1,n,x,y,cur);
}
else
{
cout<<query(1,1,n,x,y,0)<<endl;
}
}
return 0;
}