- https://www.luogu.com.cn/problem/P2801
- http://www.lydsy.com/JudgeOnline/problem.php?id=3343
维护块内最值,在查询时,面对整块做特判,否则,就暴力遍历整块。
实测可过。
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int bel[N],bl,num,n;int ans;
int a[N],add[N],mi[N],ma[N];
int read() {
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)) {
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)) {
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void build() {
bl=sqrt(n);
memset(mi,0x3f,sizeof mi);
for(int i=1;i<=n;i++) {
bel[i]=(i-1)/bl+1;
ma[bel[i]]=max(ma[bel[i]],a[i]);
mi[bel[i]]=min(mi[bel[i]],a[i]);
}
}
int ask(int l,int r,int c) {
ans=0;
for(int i=l;i<=min(r,bel[l]*bl);i++)
if(a[i]+add[bel[l]]>=c)
ans++;
if(bel[l]!=bel[r])
for(int i=(bel[r]-1)*bl+1;i<=r;i++)
if(a[i]+add[bel[r]]>=c)
ans++;
for(int i=bel[l]+1;i<=bel[r]-1;i++) {
if(c>ma[i])
continue;
if(c<=mi[i]) {
ans+=bl;
continue;
}//上述两个优化能 AC 呢
for(int j=(i-1)*bl+1;j<=i*bl;j++)
if(a[j]+add[i]>=c)
ans++;
}
return ans;
}
void change(int l,int r,int c) {
for(int i=l;i<=min(r,bel[l]*bl);i++) {
a[i]+=c;
mi[bel[i]]=min(a[i]+add[bel[i]],mi[bel[i]]);
ma[bel[i]]=max(a[i]+add[bel[i]],ma[bel[i]]);
}
if(bel[l]!=bel[r])
for(int i=(bel[r]-1)*bl+1;i<=r;i++) {
a[i]+=c;
mi[bel[i]]=min(a[i]+add[bel[i]],mi[bel[i]]);
ma[bel[i]]=max(a[i]+add[bel[i]],ma[bel[i]]);
}
for(int i=bel[l]+1;i<=bel[r]-1;i++) {
add[i]+=c;
mi[i]+=c;
ma[i]+=c;
}
}
int q;
int main() {
scanf("%d %d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build();
while(q--) {
char opt;int l,r,c;
cin>>opt;
scanf("%d %d %d",&l,&r,&c);
if(opt=='A')
printf("%d
",ask(l,r,c));
else
change(l,r,c);
}
}