支持区间修改及查询,适用于多次修改、多次询问;倍增RMQ算法仅支持区间查询,不支持区间修改。
练手题:
1.洛谷3352
2.codevs1080、1081、1082
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;
ll n,m,k,x,y,ans;
ll a[100010];
struct mc
{
ll l,r,num,down;
}tree[400000];
void build(ll l,ll r,ll num)
{
if(l==r)
{
tree[num].l=l;
tree[num].r=r;
tree[num].num=a[l];
return;
}
tree[num].l=l;
tree[num].r=r;
ll mid=(l+r)>>1;
ll t=num*2;
build(l,mid,t);
build(mid+1,r,t+1);
tree[num].num=tree[t].num+tree[t+1].num;
}
void down(const ll num)
{
ll l=tree[num].l;
ll r=tree[num].r;
if (l==r)
{
tree[num].down=0;
return;
}
ll t=num*2;
l=tree[t].l;
r=tree[t].r;
tree[t].num+=(r-l+1)*tree[num].down;
tree[t].down+=tree[num].down;
tree[t+1].num+=(r-l+1)*tree[num].down;
tree[t+1].down+=tree[num].down;
tree[num].down=0;
}
void add(ll &x,ll &y,ll num,ll k)
{
ll l=tree[num].l,r=tree[num].r;
if (l>=x&&r<=y)
{
tree[num].num+=(r-l+1)*k;
tree[num].down+=k;
return;
}
if (tree[num].down) down(num);
ll mid=(l+r)/2;
ll t=num*2;
if (y<=mid) add(x,y,t,k);
else if (x>mid) add(x,y,t+1,k);
else
{
add(x,y,t,k);
add(x,y,t+1,k);
}
tree[num].num=tree[t].num+tree[t+1].num;
}
void ask(ll l,ll r,ll num)
{
if (tree[num].down!=0) down(num);
if (tree[num].l>=x&&tree[num].r<=y)
{
ans+=tree[num].num;
return;
}
ll mid=(l+r)/2;
ll t=num*2;
if (y<=mid) ask(l,mid,t);
else if (x>mid) ask(mid+1,r,t+1);
else
{
ask(l,mid,t);
ask(mid+1,r,t+1);
}
}
int main()
{
ll n,m;
cin>>n>>m;
for (ll i=1;i<=n;i++)
cin>>a[i];
build(1,n,1);
ll p;
for (ll i=1;i<=m;i++)
{
cin>>p;
if (p==1)
{
cin>>x>>y>>k;
add(x,y,1,k);
}else
{
cin>>x>>y;
ans=0;
ask(1,n,1);
cout<<ans<<endl;
}
}
return 0;
}