构造一个序列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 ",BT::Q(r)-BT::Q(l-1)); } } return 0; }