Description
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。
每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)
CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
WD巨懒,于是他把这个回答的任务交给了你。
题解:
好久没有分块了,水了一道分块基础练习题。每一块开个数组,排好序,区间加的话,同一块就暴力加,重新排序;否则两端不完整的块暴力加,中间完整的块打标记;询问的话,同一块暴力搞;不同块的话,两端不完整的暴力搞,中间完整的在块内二分即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=1000010;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
int n,q,sz,bel[Maxn],L[Maxn],R[Maxn],a[Maxn],b[1005][1005],len[1005],lazy[1005];
int main()
{
n=read();q=read();
int sz=(int)(sqrt(n));bel[0]=-1;
for(int i=1;i<=n;i++)
{
bel[i]=(i-1)/sz+1;
if(bel[i]!=bel[i-1])L[bel[i]]=i;
R[bel[i]]=i;
}
for(int i=1;i<=n;i++)a[i]=read(),b[bel[i]][++len[bel[i]]]=a[i];
for(int i=1;i<=bel[n];i++)sort(b[i]+1,b[i]+1+len[i]);
while(q--)
{
char op[3];
scanf("%s",op);
int x=read(),y=read(),z=read();
if(op[0]=='M')
{
if(bel[x]==bel[y])
{
int o=bel[x];
for(int i=x;i<=y;i++)b[o][i-(o-1)*sz]+=z,a[i]+=z;
sort(b[o]+1,b[o]+1+len[o]);
}
else
{
int o;
o=bel[x];
for(int i=x;i<=R[o];i++)b[o][i-(o-1)*sz]+=z,a[i]+=z;
sort(b[o]+1,b[o]+1+len[o]);
o=bel[y];
for(int i=L[o];i<=y;i++)b[o][i-(o-1)*sz]+=z,a[i]+=z;
sort(b[o]+1,b[o]+1+len[o]);
for(int i=bel[x]+1;i<bel[y];i++)lazy[i]+=z;
}
}
else
{
int ans=0;
if(bel[x]==bel[y])
{
int o=bel[x];
for(int i=x;i<=y;i++)if(a[i]+lazy[o]>=z)ans++;
}
else
{
int o;
o=bel[x];
for(int i=x;i<=R[o];i++)if(a[i]+lazy[o]>=z)ans++;
o=bel[y];
for(int i=L[o];i<=y;i++)if(a[i]+lazy[o]>=z)ans++;
for(int i=bel[x]+1;i<bel[y];i++)
{
int l=1,r=len[i];
while(l<=r)
{
int mid=l+r>>1;
if(b[i][mid]+lazy[i]>=z)r=mid-1;
else l=mid+1;
}
ans+=(len[i]-r);
}
}printf("%d\n",ans);
}
}
}