看到询问个数少,分块的复杂度能过,于是人生第一次打了分块,居然A了。据说也有线段树瞎搞的,不过我不会写。
总之,边角暴力,块内二分,受影响的块直接重新排序。一切都是那么暴力。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#define N 1001000
#define ll long long
#define max(x,y) ((x)>(y) ? (x) : (y))
#define min(x,y) ((x)<(y) ? (x) : (y))
using namespace std;
inline int getint() {
int t=0,p;
char ch=getchar();
for(;ch!='-' && !(ch>='0' && ch<='9');ch=getchar());
if(ch=='-') p=-1,ch=getchar();
else p=1;
for(;ch>='0' && ch<='9';ch=getchar()) {
t=t*10+ch-48;
}
return t*p;
}
int n,q,a[N],b[N],c[N],x,y,z;
int main() {
// freopen("magic.in","r",stdin);
// freopen("magic.out","w",stdout);
n=getint();q=getint();
register int m=int(sqrt(n));
for(int i=1;i<=n;i++) {
b[i]=a[i]=getint();
}
for(int i=1;i+m<=n;i+=m+1) {
sort(b+i,b+i+m+1); //b数组表示对每个块排序的a数组
}
memset(c,0,sizeof c);
while(q--) {
char ch=getchar();
for(;ch!='A' && ch!='M';ch=getchar());
x=getint(),y=getint(),z=getint();
if(ch=='M') {
register int i=x;
int l=(m+1)*((x+m)/(m+1))-m;
int r=(m+1)*((x+m)/(m+1));
l=min(l,n);
r=min(r,n);
for(;i<=y && (i+m)%(m+1)!=0;i++) {
a[i]+=z; //边角暴力
}
if(r-l==m) {
for(int j=l;j<=r;j++) {
b[j]=a[j];
}
sort(b+l,b+r+1); //强行排序
}
for(;i+m<=y;i+=m+1) {
c[(i+m)/(m+1)]+=z; //块上统计
}
l=(m+1)*((i+m)/(m+1))-m;
r=(m+1)*((i+m)/(m+1));
l=min(l,n);
r=min(r,n);
for(;i<=y;i++) {
a[i]+=z; //边角暴力
}
if(r-l==m) {
for(int j=l;j<=r;j++) {
b[j]=a[j];
}
sort(b+l,b+r+1);
}
} else {
int acht=0;
register int i=x;
for(;i<=y && (i+m)%(m+1)!=0;i++) {
if(a[i]+c[(i+m)/(m+1)]>=z) acht++; //边角暴力
}
for(;i+m<=y;i+=m+1) {
acht+=(i+m+1-(lower_bound(b+i,b+i+m+1,z-c[(i+m)/(m+1)])-b)); //块内二分
}
for(;i<=y;i++) {
if(a[i]+c[(i+m)/(m+1)]>=z) acht++; //边角暴力
}
printf("%d\n",acht);
}
}
return 0;
}