题意:给出一个b序列,还有一个a序列初始全为0。对a有两种操作,一种是add操作,对【l,r】区间所有数加1.一种是查询,对【l,r】区间求sum ( floor(ai/bi)).
思路:用线段树来维护一个区间最小值,维护一个sum。首先将序列b插入到线段树中,每次add时对区间进行减1操作,当区间最小值减到0时,跟新sum,0重新变为b[i]。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
struct node
{
int l,r;
int lazy;
int sum,mi;
}st[maxn<<2];
int a[maxn];
void pushup(int o)
{
st[o].mi = min(st[o*2].mi,st[o*2+1].mi);
st[o].sum = st[o*2].sum + st[o*2+1].sum;
}
void pushdown(int o)
{
if(st[o].lazy)
{
st[o*2].mi -= st[o].lazy;
st[o*2+1].mi -= st[o].lazy;
st[o*2].lazy += st[o].lazy;
st[o*2+1].lazy += st[o].lazy;
st[o].lazy = 0;
}
}
void build(int o,int l,int r)
{
st[o].l = l;;
st[o].r = r;
st[o].lazy = 0;
if(l==r)
{
st[o].mi = a[l];
st[o].sum = 0;
return;
}
int mid = (l+r)>>1;
build(o*2,l,mid);
build(o*2+1,mid+1,r);
pushup(o);
}
void update(int o,int l,int r)
{
if(l<=st[o].l&&r>=st[o].r)
{
st[o].mi--;
if(st[o].mi>0)
{
st[o].lazy++;
return;
}
else
{
if(st[o].l==st[o].r)
{
st[o].sum++;
st[o].mi = a[st[o].l];
return;
}
}
}
pushdown(o);
int mid = (st[o].l+st[o].r)>>1;
if(l<=mid)
update(o*2,l,r);
if(r>mid)
update(o*2+1,l,r);
pushup(o);
}
int query(int o,int l,int r)
{
if(l<=st[o].l&&r>=st[o].r)
{
return st[o].sum;
}
pushdown(o);
int ans = 0;
int mid = (st[o].l+st[o].r)>>1;
if(l<=mid)
ans += query(o*2,l,r);
if(r>mid)
ans += query(o*2+1,l,r);
return ans;
}
int main()
{
int n,q;
while(scanf("%d%d",&n,&q)!=EOF)
{
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
build(1,1,n);;
char s[10];
int x,y;
while(q--)
{
scanf("%s%d%d",s,&x,&y);
if(s[0]=='a')
{
update(1,x,y);
}
else
{
printf("%d\n",query(1,x,y));
}
}
}
return 0;
}