给定一个数组b和一个空的数组a,要求支持两种操作:将a在从l到r上每项都加1,查询从l到r区间上之和。
由于每一个bi都是不同的,直接维护ai/bi很困难。
观察要求查询的是区间内ai/bi向下取整之和,且ai初始为0。显然ai每增加bi次,才能使结果增加1。于是我们可以把这个问题转化成,查询的区间内结果增加了多少次,也就是说,查询的区间内ai的值每增加bi一次结果就会增加1,我们需要找出区间内所有的ai增加到bi一共有多少次。
开两个线段树,其中一个线段树维护区间最小值,初始时保存的是各个bi的值。每当要求给a在l到r上增加1的时候,我们处理的方法是通过这个线段树给l到r这个区间减1。
每次减完以后,我们看一下有没有位置减到了0。如果有,则说明这个位置上ai增加到了一次bi,最终的结果需要增加1。这个时候我们找出这些位置,在另一个线段树上将这个位置的值加1,这第二个线段树维护区间和,保存的就是各个区间的答案值。
而当查询的时候,就只需要在第二个线段树上查询区间和即为答案。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 100050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
int n,m,x,y,b[maxn];
int tree[maxn<<2],lazy[maxn<<2];
int sum[maxn<<2];
char s[15];
void build(int root,int l,int r)
{
lazy[root]=sum[root]=0;
if(l==r)
{
tree[root]=b[l];
return;
}
int mid=(l+r)>>1;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
tree[root]=min(tree[root*2],tree[root*2+1]);
}
void addlazy(int root,int l,int r)
{
if(lazy[root]!=0)
{
lazy[root*2]+=lazy[root];
lazy[root*2+1]+=lazy[root];
tree[root*2]+=lazy[root];
tree[root*2+1]+=lazy[root];
lazy[root]=0;
}
}
void add(int root,int l,int r,int aiml,int aimr)
{
if(l>aimr||r<aiml)return;
if(l>=aiml&&r<=aimr)
{
lazy[root]--;
tree[root]--;
return;
}
addlazy(root,l,r);
int mid=(l+r)>>1;
add(root*2,l,mid,aiml,aimr);
add(root*2+1,mid+1,r,aiml,aimr);
tree[root]=min(tree[root*2],tree[root*2+1]);
}
void addsum(int root,int l,int r,int aim)
{
if(l>aim||r<aim)return;
if(l==r&&r==aim)
{
sum[root]++;
return;
}
int mid=(l+r)>>1;
addsum(root*2,l,mid,aim);
addsum(root*2+1,mid+1,r,aim);
sum[root]=sum[root*2]+sum[root*2+1];
}
void update(int root,int l,int r)
{
if(tree[root]>0)return;
if(l==r)
{
tree[root]=b[l];
addsum(1,1,n,l);
return;
}
addlazy(root,l,r);
int mid=(l+r)>>1;
update(root*2,l,mid);
update(root*2+1,mid+1,r);
tree[root]=min(tree[root*2],tree[root*2+1]);
}
int query(int root,int l,int r,int aiml,int aimr)
{
if(l>aimr||r<aiml)return 0;
if(l>=aiml&&r<=aimr)return sum[root];
int mid=(l+r)>>1;
return query(root*2,l,mid,aiml,aimr)+query(root*2+1,mid+1,r,aiml,aimr);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
build(1,1,n);
for(int i=0;i<m;i++)
{
scanf("%s%d%d",s,&x,&y);
if(s[0]=='a')
{
add(1,1,n,x,y);
if(tree[1]==0)
update(1,1,n);
}
else
{
int ans=query(1,1,n,x,y);
printf("%d\n",ans);
}
}
}
return 0;
}