题意:有a数组和b数组,a开始全为0,b是1~n的一个排列。有两种操作,add l r,a[l]~a[r]每一个都加1,query l r,求a[l]/b[l]+...+a[r]/b[l],每一项向下取整。
思路:线段树维护当前区间能对答案作出贡献需要加的最小次数,每次更新先区间更新,然后判断区间维护的最小值是否为0,为0则把每个答案能加一的点单点更新。
AC代码:
/*************************************************************************
> File Name: HDU-6315.cpp
> Author: cyh
> Mail:
> Created Time: 2018年07月25日 星期三 18时41分15秒
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ll t[rt].l
#define rr t[rt].r
#define rs rt<<1|1
#define ls rt<<1
const int maxn=1e5+10;
const int inf=1e9+10;
const long long INF=2e18+10;
int n,m;
struct node
{
int l,r;
int mi,sum,tag;
}t[maxn*4];
int b[maxn];
void pushup(int rt)
{
t[rt].sum=t[ls].sum+t[rs].sum;
t[rt].mi=min(t[ls].mi,t[rs].mi);
}
void build(int rt,int l,int r)
{
t[rt].l=l;
t[rt].r=r;
t[rt].sum=t[rt].tag=0;
if(l==r){
t[rt].mi=b[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
void pushdown(int rt)
{
if(t[rt].tag!=0){
int tag=t[rt].tag;
t[ls].mi+=tag;
t[rs].mi+=tag;
t[ls].tag+=tag;
t[rs].tag+=tag;
t[rt].tag=0;
}
}
void _update(int rt)
{
if(ll==rr){
t[rt].sum++;
t[rt].mi=b[ll];
return;
}
pushdown(rt);
if(t[ls].mi==0) _update(ls);
if(t[rs].mi==0) _update(rs);
pushup(rt);
}
void update(int rt,int l,int r)
{
if(l<=ll&&rr<=r){
t[rt].mi--;
t[rt].tag--;
return;
}
pushdown(rt);
int mid=(ll+rr)>>1;
if(l<=mid) update(ls,l,r);
if(r>mid) update(rs,l,r);
pushup(rt);
}
int query(int rt,int l,int r)
{
if(l<=ll&&rr<=r) return t[rt].sum;
pushdown(rt);
int mid=(ll+rr)>>1;
int ans=0;
if(l<=mid) ans+=query(ls,l,r);
if(r>mid) ans+=query(rs,l,r);
pushup(rt);
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
build(1,1,n);
char op[10];
int l,r;
while(m--){
scanf("%s%d%d",op,&l,&r);
if(op[0]=='a'){
update(1,l,r);
if(t[1].mi==0){
_update(1);
}
}
else printf("%d\n",query(1,l,r));
}
}
return 0;
}