构造一个序列B[i]=-b[i],建一颗线段树,维护区间max,
每次区间加后再询问该区间最大值,如果为0就在树状数组中对应的值+1(该操作可能进行多次)
答案在树状数组中找
其实只用一颗线段树也是可以的
Code
#include <cstdio>
#include <algorithm>
#include <cstring>
#define mst(a) memset(a,0,sizeof(a))
#define N 100010
using namespace std;
int n,m,b[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
namespace BT{
int T[N];
#define lowbit(x) ((x)&(-x))
void add(int x,int v){for(;x<=n;x+=lowbit(x))T[x]+=v;}
int Q(int x){int r=0;for(;x;x-=lowbit(x))r+=T[x];return r;}
void ntt(){mst(T);}
}
namespace Seg{
#define MID int mid=(l+r)>>1,ls=id<<1,rs=id<<1|1
int tag[N*4];
struct info{
int x,id;
info(){x=id=0;}
info(int a,int b):x(a),id(b){}
friend info operator+(info a,info b){
return a.x>b.x?a:b;
}
}T[N*4];
void build(int l,int r,int id){
if(l==r){T[id]=info(-b[l],l);return;}
MID;
build(l,mid,ls),build(mid+1,r,rs);
T[id]=T[ls]+T[rs];
}
void pushdown(int l,int r,int id){
int &tmp=tag[id];
if(!tmp)return;
MID;
tag[ls]+=tmp,tag[rs]+=tmp;
T[ls].x+=tmp,T[rs].x+=tmp;
tmp=0;
}
void upd(int l,int r,int id,int L,int R,int v){
if(L<=l&&r<=R){tag[id]+=v;T[id].x+=v;return;}
pushdown(l,r,id);
MID;
if(L<=mid)upd(l,mid,ls,L,R,v);
if(R>=mid+1)upd(mid+1,r,rs,L,R,v);
T[id]=T[ls]+T[rs];
}
info Q(int l,int r,int id,int L,int R){
if(L<=l&&r<=R){return T[id];}
pushdown(l,r,id);
MID;
info res(-1e9,0);
if(L<=mid)res=res+Q(l,mid,ls,L,R);
if(R>=mid+1)res=res+Q(mid+1,r,rs,L,R);
return res;
}
void fft(){mst(tag),mst(T);}
}
void fwt(){Seg::fft(),BT::ntt();}
int main(){
for(;~scanf("%d%d",&n,&m);){
fwt();
for(int i=1;i<=n;++i)b[i]=read();
Seg::build(1,n,1);
for(int i=1;i<=m;++i){
char s[10];scanf("%s",s);
int l=read(),r=read();
if(s[0]=='a'){
Seg::upd(1,n,1,l,r,1);
for(;;){
Seg::info tmp=Seg::Q(1,n,1,l,r);
if(tmp.x==0){
Seg::upd(1,n,1,tmp.id,tmp.id,-b[tmp.id]);
BT::add(tmp.id,1);
}else break;
}
}else printf("%d\n",BT::Q(r)-BT::Q(l-1));
}
}
return 0;
}