第一次写分块。黄学长的模板好漂亮。
由于既要保存原始的位置关系,又要有分块的排序,所以开两个数组。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define maxn 1005000 using namespace std; long long n,q,a[maxn],b[maxn],x,y,z,block,pos[maxn],cnt,add[maxn]; char type[5]; void reset(long long x) { long long l=(x-1)*block+1,r=min(x*block,n); for (long long i=l;i<=r;i++) b[i]=a[i]; sort(b+l,b+r+1); } void modify(long long x,long long y,long long z) { if (pos[x]==pos[y]) { for (long long i=x;i<=y;i++) a[i]+=z; } else { for (long long i=x;i<=pos[x]*block;i++) a[i]+=z; for (long long i=(pos[y]-1)*block+1;i<=y;i++) a[i]+=z; for (long long i=pos[x]+1;i<=pos[y]-1;i++) add[i]+=z; } reset(pos[x]);reset(pos[y]); } long long find(long long x,long long r) { long long left=(x-1)*block+1,right=min(x*block,n),last=right; while (left<=right) { long long mid=(left+right)>>1; if (b[mid]<r) left=mid+1; else right=mid-1; } return last-left+1; } long long ask(long long x,long long y,long long z) { long long sum=0; if (pos[x]==pos[y]) { for (long long i=x;i<=y;i++) if (a[i]+add[pos[i]]>=z) sum++; return sum; } else { for (long long i=x;i<=pos[x]*block;i++) if (a[i]+add[pos[i]]>=z) sum++; for (long long i=(pos[y]-1)*block+1;i<=y;i++) if (a[i]+add[pos[i]]>=z) sum++; for (long long i=pos[x]+1;i<=pos[y]-1;i++) sum=sum+find(i,z-add[i]); return sum; } } int main() { scanf("%lld%lld",&n,&q); block=sqrt(n); for (long long i=1;i<=n;i++) { scanf("%lld",&a[i]); if (i%block==0) pos[i]=i/block; else pos[i]=i/block+1; } cnt=pos[n]; for (long long i=1;i<=cnt;i++) reset(i); for (long long i=1;i<=q;i++) { scanf("%s%lld%lld%lld",type,&x,&y,&z); if (type[0]=='M') modify(x,y,z); else printf("%lld ",ask(x,y,z)); } return 0; }