- 题意
给你一个序列,每个序列有一个值。支持两种操作:
1.区间加减。
2.区间查询比C小的数的个数。
- 题解
有想法的人可以看出树套树可做。时间复杂度 O(m⋅log2n) 。
当然没想法的人可以直接写暴力,分块大法好。。时间复杂度 O(m⋅n√⋅logn√)
分块做可以说是道很简单的题了。先对每个块内部排序。对于查询,只需要在完整块中二分查找,不完整块中暴力枚举。对于修改操作,完整块打标记,不完整块暴力重构。
(
S=2200
比
S=n√=1000
更好,这个可以打表算出来。。)
打表代码:
for(int s=1000;s<=10000;s++)
{
cout<<s<<" : "<<(double)n/(double)s*(log(s)/(log(2)))+s+s<<endl;
}
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int Maxn=1e6+50;
const int S=2500;
const int K=500;
inline int read()
{
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
int buf[50];
inline void W(int x)
{
if(!x)putchar('0');
if(x<0)putchar('-'),x=-x;
while(x)buf[++buf[0]]=x%10,x/=10;
while(buf[0])putchar('0'+buf[buf[0]--]);
}
int n,Q,s,a[Maxn],bg[K+50],ed[K+50],add[K+50],b[Maxn];
inline void pre()
{
for(int i=1;i*S<=n;i++){s=i,bg[i]=ed[i-1]+1,ed[i]=ed[i-1]+S;}
if(ed[s]!=n){++s,bg[s]=ed[s-1]+1,ed[s]=n;}
for(int i=1;i<=s;i++)sort(b+bg[i],b+ed[i]+1);
}
inline void rebuild(int x)
{
for(int i=bg[x];i<=ed[x];i++)b[i]=a[i];
sort(b+bg[x],b+ed[x]+1);
}
inline int calc(int now,int val)
{
int L;
int l=bg[now],r=ed[now];
while(l<=r)
{
int mid=(l+r)>>1;
if(b[mid]>=val)r=mid-1;
else l=mid+1,L=mid;
}
if(r==(bg[now]-1))L=bg[now]-1;
return ed[now]-L;
}
int main()
{
n=read();Q=read();
for(int i=1;i<=n;i++)a[i]=b[i]=read();
pre();
while(Q--)
{
char ch[2];
scanf("%s",ch+1);
if(ch[1]=='A')
{
int l=read(),r=read(),c=read();
int ans=0;
if(r-l+1>2*S)
{
int L=(l-1)/S+1,R=(r-1)/S+1;
if(bg[L]!=l)L++;
if(ed[R]!=r)R--;
for(int i=L;i<=R;i++)ans+=calc(i,c-add[i]);
for(int i=l;i<bg[L];i++)if((a[i]+add[L-1])>=c)ans++;
for(int i=ed[R]+1;i<=r;i++)if((a[i]+add[R+1])>=c)ans++;
}
else
{
for(int i=l;i<=r;i++)if((a[i]+add[(i-1)/S+1])>=c)ans++;
}
W(ans);putchar('\n');
}
else if(ch[1]=='M')
{
int l=read(),r=read(),c=read();
if(r-l+1>2*S)
{
int L=(l-1)/S+1,R=(r-1)/S+1;
if(bg[L]!=l)L++;
if(ed[R]!=r)R--;
for(int i=L;i<=R;i++)add[i]+=c;
for(int i=l;i<bg[L];i++){a[i]+=c;}
if(bg[L]!=l)rebuild(L-1);
for(int i=ed[R]+1;i<=r;i++){a[i]+=c;}
if(ed[R]!=r)rebuild(R+1);
}
else
{
for(int i=l;i<=r;i++)a[i]+=c;
int t1=(l-1)/S+1,t2=(r-1)/S+1;
if(t1==t2)rebuild(t1);
else if(t1==t2-1)rebuild(t1),rebuild(t2);
else rebuild(t1),rebuild(t1+1),rebuild(t2);
}
}
}
}