牛客小白月赛20 E 区区区间
算法分析
线段树,区间修改,区间查询,要用到lazy数组去更新(查询和更新过程都要去更新)
代码实现
#include<iostream>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
struct node
{
int l,r;
ll sum,lazy;
}tr[maxn<<2];
ll a[maxn];
void up(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;//更新和
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r;
if(l==r)
{
tr[u].sum=a[l];
tr[u].lazy=0;//初始化
return ;
}
ll mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
up(u);
}
void pushdown(int u)
{
if(tr[u].lazy)//如果父亲结点有lazy就下放给孩子结点
{//根据题目修改下面的就行,题目是从k加到k+r-l
tr[u<<1].lazy=tr[u].lazy;//所以左边为k,右边为右端点减去左端点+k
tr[u<<1|1].lazy=(tr[u].lazy+tr[u<<1].r-tr[u<<1].l+1);
tr[u<<1].sum=(2*tr[u<<1].lazy+tr[u<<1].r-tr[u<<1].l)*(tr[u<<1].r-tr[u<<1].l+1)/2;
tr[u<<1|1].sum=(2*tr[u<<1|1].lazy+tr[u<<1|1].r-tr[u<<1|1].l)*(tr[u<<1|1].r-tr[u<<1|1].l+1)/2;
tr[u].lazy=0;//加完后就清0
//更新和的过程是首项加末项乘于项数/2
}
}
void updata(int u,int L,int R,ll data)
{
if(L<=tr[u].l&&tr[u].r<=R)
{
tr[u].lazy=(data+tr[u].l-L);
tr[u].sum=(2*tr[u].lazy+tr[u].r-tr[u].l)*(tr[u].r-tr[u].l+1)/2;
return ;
}
int mid=tr[u].l+tr[u].r>>1;
pushdown(u);//更新
if(mid>=L)
updata(u<<1,L,R,data);
if(mid<R)
updata(u<<1|1,L,R,data);
up(u);
}
ll quary(int u,int l,int r)
{
ll res=0;
if(tr[u].l>=l&&tr[u].r<=r)
return tr[u].sum;
int mid=tr[u].l+tr[u].r>>1;
pushdown(u);//更新
if(mid>=l)
res+=quary(u<<1,l,r);
if(mid<r)
res+=quary(u<<1|1,l,r);
return res;
}
int main()
{
ll n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
int flag,l,r;
ll x;
while(m--)
{
scanf("%d%d%d",&flag,&l,&r);
if(flag==1)
{
scanf("%lld",&x);
updata(1,l,r,x);
}
else
{
ll res=quary(1,l,r);
cout<<res<<endl;
}
}
}