传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3343
思路:分块大法好...
分块,每块内部保持有序。
修改时,给完整的块打标记,两段不完整的暴力改
询问时,给完整的块二分查找,两段不完整的暴力查。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=1000010,maxk=2010;
using namespace std;
int n,m,q;char op[5],ch;
struct Block{
int a[maxn],b[maxn],add[maxk],pos[maxn],sz;
void clear(int x){
int l=(x-1)*sz+1,r=min(x*sz,n);
for (int i=l;i<=r;i++) b[i]=a[i];
sort(b+l,b+r+1);
}
void change(int x,int y,int v){
if (pos[x]==pos[y]) for (int i=x;i<=y;i++) a[i]+=v;
else{
for (int i=x;i<=pos[x]*sz;i++) a[i]+=v;
for (int i=(pos[y]-1)*sz+1;i<=y;i++) a[i]+=v;
}
clear(pos[x]),clear(pos[y]);
for (int i=pos[x]+1;i<pos[y];i++) add[i]+=v;
}
int find(int x,int v){
int l=(x-1)*sz+1,r=min(x*sz,n),mid=(l+r)>>1,cnt=r;
while (l<=r){
if (b[mid]>=v) r=mid-1;
else l=mid+1;
mid=(l+r)>>1;
}
return cnt-l+1;
}
int query(int x,int y,int v){
int sum=0;
if (pos[x]==pos[y]) for (int i=x;i<=y;i++) sum+=(a[i]+add[pos[i]]>=v);
else{
for (int i=x;i<=pos[x]*sz;i++) sum+=(a[i]+add[pos[i]]>=v);
for (int i=(pos[y]-1)*sz+1;i<=y;i++) sum+=(a[i]+add[pos[i]]>=v);
}
for (int i=pos[x]+1;i<pos[y];i++) sum+=find(i,v-add[i]);
return sum;
}
}T;
void read(int &x){
for (ch=getchar();!isdigit(ch);ch=getchar());
for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
int main(){
scanf("%d%d",&n,&q);T.sz=(int)sqrt(n);
for (int i=1;i<=n;i++){
read(T.a[i]),T.pos[i]=(i-1)/T.sz+1;
}
m=n/T.sz+(n%T.sz?1:0);
for (int i=1;i<=m;i++) T.clear(i);
for (int i=1,x,y,z;i<=q;i++){
scanf("%s",op);read(x),read(y),read(z);
if (op[0]=='M') T.change(x,y,z);
else printf("%d\n",T.query(x,y,z));
}
return 0;
}