在面对数据范围比较大,但是实际上并非范围中的每个点都要用到的时候,我们可以采取动态开点的策略,也就是用到哪个开哪个
e g . eg. eg. 已知一个数列,你需要进行下面两种操作:
- 将某区间每一个数加上 k k k
- 求出某区间的和
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long ll;
ll sz[maxn<<1],lazy[maxn<<1];
int L[maxn<<1],R[maxn<<1];
int cnt=1;
int n,m;
inline void Pushup(int &rt){}
inline void Pushdown(int k,int l,int r){
if(lazy[k]){
if(!L[k])L[k]=++cnt;
if(!R[k])R[k]=++cnt;
lazy[L[k]]+=lazy[k];
lazy[R[k]]+=lazy[k];
int mid=(l+r)>>1;
sz[L[k]]+=(mid-l+1)*lazy[k];
sz[R[k]]+=(r-mid)*lazy[k];
lazy[k]=0;
}
}
inline void build(int &rt,int l,int r,int pos,int x){
if(!rt)rt=++cnt;//动态开点
if(l==r){
sz[rt]=x;return;
}
int mid=(l+r)>>1;
if(pos<=mid)build(L[rt],l,mid,pos,x);
else build(R[rt],mid+1,r,pos,x);
sz[rt]=sz[L[rt]]+sz[R[rt]];
}
inline void update(int &rt,int l,int r,int lpos,int rpos,int x){
if(!rt)rt=++cnt;
if(lpos<=l&&rpos>=r){
lazy[rt]+=x;sz[rt]+=(r-l+1)*x;
return;
}
Pushdown(rt,l,r);
int mid=(l+r)>>1;
if(lpos<=mid)update(L[rt],l,mid,lpos,rpos,x);
if(rpos>mid)update(R[rt],mid+1,r,lpos,rpos,x);
sz[rt]=sz[L[rt]]+sz[R[rt]];
}
inline ll query(int rt,int l,int r,int lpos,int rpos){
if(!rt)return 0;
if(lpos<=l&&rpos>=r)return sz[rt];
Pushdown(rt,l,r);
int mid=(l+r)>>1;
ll ans=0;
if(lpos<=mid)ans+=query(L[rt],l,mid,lpos,rpos);
if(rpos>mid)ans+=query(R[rt],mid+1,r,lpos,rpos);
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int x;int tmp=1;
scanf("%d",&x);
build(tmp,1,n,i,x);
}
for(int i=1;i<=m;i++){
int q;
scanf("%d",&q);
if(q==1){
int lpos,rpos,x;
scanf("%d%d%d",&lpos,&rpos,&x);
int temp=1;
update(temp,1,n,lpos,rpos,x);
}else{
int lpos,rpos;
scanf("%d%d",&lpos,&rpos);
printf("%lld\n",query(1,1,n,lpos,rpos));
}
}
return 0;
}