分块,代码中有注释,并不难理解
代码
//By AcerMo
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=1e6+50;
int n,m;
int block,cnt;
int a[M],b[M],bloc[M],add[M];
//add数组存储没个大块的整体加
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline int get(int x,int z)
{
int l=(x-1)*block+1,r=min(x*block,n);
while (l<=r)
{
int mid=(l+r)>>1;
if (b[mid]<z) l=mid+1;
else r=mid-1;
}
return (min(x*block,n)-l+1);
} //二分一下有多少大于的
inline int query(int x,int y,int z)
{
int ans=0;
if (bloc[x]==bloc[y])
{for (int i=x;i<=y;i++)
if (a[i]+add[bloc[i]]>=z) ans++;}//同一个块,暴力累加
else
{
for (int i=x;i<=bloc[x]*block;i++)
if (a[i]+add[bloc[i]]>=z) ans++;//边角余料
for (int i=(bloc[y]-1)*block+1;i<=y;i++)//同
if (a[i]+add[bloc[i]]>=z) ans++;
}
for (int i=bloc[x]+1;i<bloc[y];i++) ans+=get(i,z-add[i]);//完整的大块
return ans;
}
inline void reset(int x)
{
int l=(x-1)*block+1,r=min(x*block,n);//因为可能出界
for (int i=l;i<=r;i++) b[i]=a[i];
sort(b+l,b+r+1);
return ;
}
inline void adda(int x,int y,int z)
{
if (bloc[x]==bloc[y])
for (int i=x;i<=y;i++) a[i]+=z;//同一个块,直接暴力累加
else
{
for (int i=x;i<=bloc[x]*block;i++) a[i]+=z;//处理x与y所在块的边角余料
for (int i=(bloc[y]-1)*block;i<=y;i++) a[i]+=z;//同
}
reset(bloc[x]);reset(bloc[y]);//排序
for (int i=bloc[x]+1;i<bloc[y];i++) add[i]+=z;//区间整体+z
return ;
}
int main()
{
n=read();m=read();block=sqrt(n);
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=n;i++)
bloc[i]=(i-1)/block+1,b[i]=a[i];
if (n%block) cnt=n/block+1;
else cnt=n/block;
for (int i=1;i<=cnt;i++) reset(i);
for (int i=1;i<=m;i++)
{
char fl[3];int x,y,z;
scanf("%s%d%d%d",fl,&x,&y,&z);
if (fl[0]=='M') adda(x,y,z);
else cout<<query(x,y,z)<<endl;
}
return 0;
}