教主的魔法
分块题,结果写了线段树。
查询的是区间内大于等于\(C\)的元素个数,维护一下区间最小值,修改照常,查询的时候改一下,如果碰到区间最小值都大于等于\(C\),就计算贡献,否则就继续往下分,这样就得到了整个区间内的个数。复杂度还是\(O(nlogn)\)。
#include<cstdio>
#define R register
#define I inline
using namespace std;
const int S=1000003,M=4000003,inf=0x7fffffff;
int a[M],t[M],h[S],n,u;
I int min(int x,int y){return x<y?x:y;}
I void upd(int k,int v){a[k]+=v,t[k]+=v;}
I void psu(int k,int p,int q){a[k]=min(a[p],a[q]);}
I void psd(int k,int p,int q){upd(p,t[k]),upd(q,t[k]),t[k]=0;}
void bld(int k,int l,int r){
if(l==r){a[k]=h[l]; return ;}
R int m=l+r>>1,p=k<<1,q=p|1;
bld(p,l,m),bld(q,m+1,r),psu(k,p,q);
}
void mdf(int k,int l,int r,int x,int y,int v){
if(x<=l&&r<=y){upd(k,v); return ;}
R int m=l+r>>1,p=k<<1,q=p|1;
psd(k,p,q);
if(x<=m) mdf(p,l,m,x,y,v);
if(m<y) mdf(q,m+1,r,x,y,v);
psu(k,p,q);
}
int qry(int k,int l,int r,int x,int y,int c){
if(l==r&&a[k]<c) return a[k];
if(x<=l&&r<=y&&a[k]>=c){u+=r-l+1; return a[k];}
R int m=l+r>>1,p=k<<1,q=p|1,o=inf;
psd(k,p,q);
if(x<=m) o=min(o,qry(p,l,m,x,y,c));
if(m<y) o=min(o,qry(q,m+1,r,x,y,c));
return o;
}
int main(){
R int q,i,x,y,z;
R char p[2];
scanf("%d%d",&n,&q);
for(i=1;i<=n;++i) scanf("%d",&h[i]);
bld(1,1,n);
for(i=1;i<=q;++i){
scanf("%s%d%d%d",p,&x,&y,&z);
if(p[0]=='M')
mdf(1,1,n,x,y,z);
else
u=0,qry(1,1,n,x,y,z),printf("%d\n",u);
}
return 0;
}