题目大意:维护数列,资磁区间加,询问区间内大于等于C的数的个数
题解:分块
将原数组复制一份副本,维护其单调性
修改:同一块/不完整块直接加,整块打标记,重构不完整块(块内不一定单调)
查询:同一块/不完整块暴力,整块二分
初始化要重构所有块
O(Qn−−√logn)
O
(
Q
n
log
n
)
我的收获:分块T1达成
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int M=1000005;
#define opes for(int i=l;i<=r;i++)
#define opel for(int i=l;i<=min(pos[l]*blo,r);i++)
#define oper for(int i=(pos[r]-1)*blo+1;i<=r;i++)
#define opea for(int i=pos[l]+1;i<=pos[r]-1;i++)
int n,q,m,blo,tot;
int a[M],b[M],pos[M],add[M];
void reset(int x)
{
int l=(x-1)*blo+1,r=min(x*blo,n);//找块的左右端点
opes b[i]=a[i];
sort(b+l,b+r+1);//左闭右开
}
int find(int x,int v)
{
int l=(x-1)*blo+1,r=min(x*blo,n);
int ans=lower_bound(b+l,b+r+1,v)-b;//找到大于等于v的第一个数
return r-ans+1;//右端点-左端点=区间长度
}
void update(int l,int r,int v)
{
if(pos[l]==pos[r]) opes a[i]+=v;
else
{
opel a[i]+=v;
oper a[i]+=v;
opea add[i]+=v;
reset(pos[l]);reset(pos[r]);
}
}
int query(int l,int r,int v)
{
int ret=0;
if(pos[l]==pos[r]) opes ret+=a[i]+add[pos[i]]>=v;
else
{
opel ret+=a[i]+add[pos[i]]>=v;
oper ret+=a[i]+add[pos[i]]>=v;
opea ret+=find(i,v-add[i]);
}
return ret;
}
void work()
{
char opt[5];
int x,y,z;
while(m--){
scanf("%s%d%d%d",opt,&x,&y,&z);
if(opt[0]=='M') update(x,y,z);
if(opt[0]=='A') printf("%d\n",query(x,y,z));
}
}
void init()
{
cin>>n>>m;blo=sqrt(n);tot=(n-1)/blo+1;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),pos[i]=(i-1)/blo+1,b[i]=a[i];
for(int i=1;i<=tot;i++) reset(i);
}
int main()
{
init();
work();
return 0;
}