题目
支持两个操作:
- 在区间 [ l ∼ r ] [l\sim r] [l∼r]增加 x x x
- 在区间 [ l ∼ r ] [l\sim r] [l∼r]查询 ≥ x \geq x ≥x的个数
分析
第二个操作太困难了,所以说尝试分块,在块内排序,二分答案,块外暴力,对于块内的区间加,可以加上懒标记,二分时减掉这个数
代码
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
using namespace std;
const int N=1000001;
int pos[N],l[N],r[N],b[N],a[N],lazy[N],n,bk,m,cnt;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void update(int x,int y,int z){
if (pos[x]==pos[y]){
for (rr int i=l[pos[x]];i<=r[pos[y]];++i) a[i]+=z*(i>=x&&i<=y),b[i]=a[i];
sort(b+l[pos[x]],b+1+r[pos[y]]);
return;
}
for (rr int i=l[pos[x]];i<=r[pos[x]];++i) a[i]+=z*(i>=x),b[i]=a[i];
for (rr int i=l[pos[y]];i<=r[pos[y]];++i) a[i]+=z*(i<=y),b[i]=a[i];
sort(b+l[pos[x]],b+1+r[pos[x]]),sort(b+l[pos[y]],b+1+r[pos[y]]);
for (rr int i=pos[x]+1;i<pos[y];++i) lazy[i]+=z;
}
inline signed ef(int l1,int r1,int w){
rr int t=r1; ++r1;
while (l1<r1){
rr int mid=(l1+r1)>>1;
if (b[mid]<w) l1=mid+1;
else r1=mid;
}
return t-l1+1;
}
inline signed query(int x,int y,int z){
rr int ans=0;
if (pos[x]==pos[y]){
for (rr int i=x;i<=y;++i)
ans+=a[i]+lazy[pos[i]]>=z;
}
else{
for (rr int i=x;i<=r[pos[x]];++i) ans+=a[i]+lazy[pos[i]]>=z;
for (rr int i=l[pos[y]];i<=y;++i) ans+=a[i]+lazy[pos[i]]>=z;
for (rr int i=pos[x]+1;i<pos[y];++i) ans+=ef(l[i],r[i],z-lazy[i]);
}
return ans;
}
signed main(){
n=iut(); m=iut(); bk=pow(n,9.0/17); cnt=n/bk+(n%bk>0);
for (rr int i=1;i<=n;++i) b[i]=a[i]=iut();
for (rr int i=1;i<=n;++i) pos[i]=(i-1)/bk+1;
for (rr int i=1;i<=cnt;++i) l[i]=r[i-1]+1,r[i]=i*bk; r[cnt]=n;
for (rr int i=1;i<=cnt;++i) sort(b+l[i],b+1+r[i]);
while (m--){
rr char c=getchar();
while (!isalpha(c)) c=getchar();
rr int x=iut(),y=iut(),z=iut();
if (c=='A') print(query(x,y,z)),putchar(10);
else update(x,y,z);
}
return 0;
}