分析
模板题。
区间修改+区间查询。
注意懒标记的添加和传递
懒标记:只修改对查询有用的节点。若遍历到的点带有懒标记,立即修改单点信息,并下放标记到左右儿子,而左右子树的信息不变,到时遍历到再修改,不用每次修改,很省时间。
上代码
我也不知道为什么用了struct会错。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,q,a[1000010];
int lazy[4000010];
ll s[4000010];
void build(int k,int l,int r)
{
if(l==r)
{
s[k]=a[l];
return;
}
int mid=(l+r)/2;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
s[k]=s[k*2]+s[k*2+1];
}
void addlazy(int k,int l,int r,int v)
{
lazy[k]+=v;
s[k]+=(ll)v*(ll)(r-l+1);
}
void pushdown(int k,int l,int r,int mid)
{
if(!lazy[k]) return;
addlazy(k*2,l,mid,lazy[k]);
addlazy(k*2+1,mid+1,r,lazy[k]);
lazy[k]=0;
}
void change(int k,int l,int r,int x,int y,int v)
{
if(x<=l&&r<=y)
{
addlazy(k,l,r,v);
return;
}
int mid=(l+r)/2;
pushdown(k,l,r,mid);
if(x<=mid) change(k*2,l,mid,x,y,v);
if(y>mid) change(k*2+1,mid+1,r,x,y,v);
s[k]=s[k*2]+s[k*2+1];
}
ll query(int k,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
{
return s[k];
}
int mid=(l+r)/2;
ll ans=0;
pushdown(k,l,r,mid);
if(x<=mid) ans+=query(k*2,l,mid,x,y);
if(y>mid) ans+=query(k*2+1,mid+1,r,x,y);
return ans;
}
int main()
{
cin>>n>>q;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
build(1,1,n);
while(q--)
{
int t,l,r;
scanf("%d%d%d",&t,&l,&r);
if(t==1)
{
int x;
scanf("%d",&x);
change(1,1,n,l,r,x);
}
else cout<<query(1,1,n,l,r)<<endl;
}
return 0;
}
2022.8.2UPD:一年之后前来复习该算法,结构体一次就A了。
2022.8.20再次UPD:省去了建树的操作,进来一个直接插入更新,感觉这样子好一点,篇幅短了。改掉了上次的代码。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node
{
int lazy;
ll s;
}tr[4000010];
int n,m;
void addlazy(int k,int l,int r,int v)
{
tr[k].lazy+=v;
tr[k].s+=(ll)(r-l+1)*(ll)(v);
}
void pushdown(int k,int l,int r,int mid)
{
if(!tr[k].lazy) return;
addlazy(k*2,l,mid,tr[k].lazy);
addlazy(k*2+1,mid+1,r,tr[k].lazy);
tr[k].lazy=0;
}
void update(int k,int l,int r,int x,int y,int v)
{
if(x<=l&&r<=y)
{
addlazy(k,l,r,v);
return;
}
int mid=(l+r)/2;
pushdown(k,l,r,mid);
if(x<=mid) update(k*2,l,mid,x,y,v);
if(y>mid) update(k*2+1,mid+1,r,x,y,v);
tr[k].s=tr[k*2].s+tr[k*2+1].s;
}
ll query(int k,int l,int r,int x,int y)
{
if(x<=l&&r<=y) return tr[k].s;
ll ans=0,mid=(l+r)/2;
pushdown(k,l,r,mid);
if(x<=mid) ans+=query(k*2,l,mid,x,y);
if(y>mid) ans+=query(k*2+1,mid+1,r,x,y);
return ans;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int t;
scanf("%d",&t);
update(1,1,n,i,i,t);
}
for(int i=1;i<=m;i++)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==1)
{
int v;
scanf("%d",&v);
update(1,1,n,x,y,v);
}
else cout<<query(1,1,n,x,y)<<endl;
}
return 0;
}