学习分块,先过一道题,感觉直接码代码可以更好理解思想
这题是最基本的操作
每次修改:如果两头在同一个块里直接暴力重构
不在同一个块里的话对中间完整的块的打标记
两头若有多余暴力重构
每次询问:如果两头在同一个块里直接暴力找一遍
不在同一块里对中间完整的块二分算答案
两头多出来的部分暴力找
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 1000010
#define M 1010
using namespace std;
int qn,n,q,size;
int bl[N],a[N],b[N],l[M],r[M],tab[M];
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);
}
void change(int x,int y,int w)
{
if(bl[x]==bl[y])
{
for(int i=x;i<=y;++i)
a[i]+=w;
rebuild(bl[x]);
}
else
{
for(int i=bl[x]+1;i<=bl[y]-1;++i) tab[i]+=w;
for(int i=x;i<=r[bl[x]];++i) a[i]+=w;
rebuild(bl[x]);
for(int i=l[bl[y]];i<=y;++i) a[i]+=w;
rebuild(bl[y]);
}
}
int solve(int x,int y,int c)
{
int l=x,r=y,ans=y+1,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(b[mid]<c) l=mid+1;
else ans=mid,r=mid-1;
}
return y-ans+1;
}
int ask(int x,int y,int c)
{
int res=0;
if(bl[x]==bl[y])
{
for(int i=x;i<=y;++i)
if(a[i]>=c) ++res;
}
else
{
for(int i=bl[x]+1;i<=bl[y]-1;++i) res+=solve(l[i],r[i],c-tab[i]);
for(int i=x;i<=r[bl[x]];++i)
if(a[i]>=c) ++res;
for(int i=l[bl[y]];i<=y;++i)
if(a[i]>=c) ++res;
}
return res;
}
int main()
{
scanf("%d %d",&qn,&q);
size=(int)sqrt(qn);
n=(qn-1)/size+1;
for(int i=1;i<=qn;++i)
{
if(!l[(i-1)/size+1]) l[(i-1)/size+1]=i;
r[(i-1)/size+1]=i;
bl[i]=(i-1)/size+1;
}
for(int i=1;i<=qn;++i)
scanf("%d",&a[i]),b[i]=a[i];
for(int i=1;i<=n;++i)
sort(b+l[i],b+r[i]+1);
while(q--)
{
char c=getchar();
while(c!='M'&&c!='A')
c=getchar();
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
if(c=='M')
change(x,y,z);
else printf("%d\n",ask(x,y,z));
}
return 0;
}