算是第一次写分块吧。
这道题是最裸的分块,每个块上打上加标记,另外维护一个块内的排好序的数组。
对于修改操作,
如果l,r在一个块内,暴力更改,之后重建。
如果l,r不在一个块内,中间的块处理标记,其余部分暴力更改,之后重建。
对于询问操作,
如果l,r在一个块内,暴力查询
如果l,r不在一个块内,中间的块里二分查找,其余部分暴力查询
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #define maxn 1010000 using namespace std; int l[1010],r[1010]; int tag[1010]; int a[maxn],b[maxn],bel[maxn]; char s[10]; int n,m,tot,block,T; void rebuild(int x) { for (int i=l[x];i<=r[x];i++) b[i]=a[i]; sort(b+l[x],b+r[x]+1); } int solve(int L,int R,int c) { int l=L,r=R,ans=R+1; while (l<=r) { int mid=(l+r)/2; if (b[mid]<c) l=mid+1; else ans=mid,r=mid-1; } return R-ans+1; } int main() { scanf("%d%d",&n,&T); block=(int)sqrt(n);tot=(n-1)/block+1; for (int i=1;i<=n;i++) { if (!l[(i-1)/block+1]) l[(i-1)/block+1]=i; r[(i-1)/block+1]=i; bel[i]=(i-1)/block+1; } for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++) b[i]=a[i]; for (int i=1;i<=tot;i++) sort(b+l[i],b+r[i]+1); while (T--) { int x,y,z; scanf("%s%d%d%d",s,&x,&y,&z); if (s[0]=='M') { if (bel[x]==bel[y]) { for (int i=x;i<=y;i++) a[i]+=z; rebuild(bel[x]); } else { for (int i=bel[x]+1;i<=bel[y]-1;i++) tag[i]+=z; for (int i=x;i<=r[bel[x]];i++) a[i]+=z; rebuild(bel[x]); for (int i=l[bel[y]];i<=y;i++) a[i]+=z; rebuild(bel[y]); } } else { int ans=0; if (bel[x]==bel[y]) { for (int i=x;i<=y;i++) if (a[i]>=z) ans++; printf("%d\n",ans); } else { for (int i=bel[x]+1;i<=bel[y]-1;i++) ans+=solve(l[i],r[i],z-tag[i]); for (int i=x;i<=r[bel[x]];i++) if (a[i]>=z) ans++; for (int i=l[bel[y]];i<=y;i++) if (a[i]>=z) ans++; printf("%d\n",ans); } } } return 0; }