题意是给一个长度为n的a,b数组,然后有2种操作,一种是a数组l~r区间+1,第二种是查询l~r区间ai/bi之和。维护区间内最大的a值和最小的b值,对一段区间进行成段更新后,如果maxa==minb说明往该节点的儿子节点更新可能会对该区间之和产生贡献,那就更新下去,往下面更新时若找到了maxa==minb的叶子节点,则该叶子节点的minb加上其初始的值(b[l]),且区间和++,比如说2/2,将分母即该节点的minb+b[l],区间之和加1.若maxa<minb的话说明往该节点的儿子节点更新不可能会对该区间之和产生贡献,因此不必更新下去了,在当前节点打个标记即可,查询的话就和普通线段树查询一样。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
#define ll long long
#define ls 2*rt
#define rs 2*rt+1
struct node
{
ll sum;
int l,r,lazy,maxa,minb;
bool tag;
}tree[4*maxn];
int b[maxn+10];
inline void pushup(int rt)
{
tree[rt].sum=tree[ls].sum+tree[rs].sum;
tree[rt].maxa=max(tree[ls].maxa,tree[rs].maxa);
tree[rt].minb=min(tree[ls].minb,tree[rs].minb);
}
inline void pushdown(int rt)
{
if(tree[rt].tag)
{
tree[ls].maxa+=tree[rt].lazy;
tree[rs].maxa+=tree[rt].lazy;
tree[ls].tag=true;
tree[ls].lazy+=tree[rt].lazy;
tree[rs].tag=true;
tree[rs].lazy+=tree[rt].lazy;
tree[rt].tag=false;
tree[rt].lazy=0;
}
}
void build(int l,int r,int rt)
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].tag=false;
tree[rt].lazy=0;
if(l==r)
{
tree[rt].maxa=0;
tree[rt].minb=b[l];
tree[rt].sum=0;
return ;
}
int mid=(l+r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
pushup(rt);
}
void update(int l,int r,int rt)
{
if(tree[rt].l>=l&&tree[rt].r<=r)
{
tree[rt].maxa++;
if(tree[rt].maxa<tree[rt].minb)///满足该条件则对rt节点对应区间更新不可能对区间和有贡献,当然ls,rs也是一样不会有贡献的,因此不必更新到rt对应区间的每个叶子节点
{
tree[rt].tag=true;
tree[rt].lazy++;
return ;
}
else
if(tree[rt].l==tree[rt].r)///满足该条件说明这个rt节点对应区间的maxa==minb,说明更新该节点是对区间和有贡献的,且rt节点是叶子节点
{
tree[rt].sum++;
tree[rt].minb+=b[tree[rt].l];
return ;
}
}
///执行下面的语句的话,说明rt节点不能成段更新或rt节点能成段更新,更新该节点对应的区间可能对区间和有贡献。这2种情况都需要更新到rt的儿子
pushdown(rt);
int mid=(tree[rt].l+tree[rt].r)/2;
if(mid>=r)
update(l,r,ls);
else
if(mid+1<=l)
update(l,r,rs);
else
{
update(l,r,ls);
update(l,r,rs);
}
pushup(rt);
}
ll query(int l,int r,int rt)
{
if(tree[rt].l>=l&&tree[rt].r<=r)
{
return tree[rt].sum;
}
ll ans=0;
int mid=(tree[rt].l+tree[rt].r)>>1;
if(mid>=r)
ans=query(l,r,ls);
else
if(mid+1<=l)
ans=query(l,r,rs);
else
{
ans=query(l,r,ls);
ans+=query(l,r,rs);
}
return ans;
}
int main()
{
int n,q;
while(scanf("%d %d",&n,&q)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d",&(b[i]));
build(1,n,1);
char op[10];
int l,r;
while(q--)
{
scanf("%s %d %d",op,&l,&r);
if(op[0]=='a')
update(l,r,1);
else
printf("%lld\n",query(l,r,1));
}
}
return 0;
}