背景:
最近学习了分块——优秀的暴力。
题意:
个数,两种操作:
操作,将
的数加上
;
操作,询问
中不小于
的数的个数。
思路:
显然是主席树
的模板题,但是要学以致用。
考虑分块。
分块的本质就是将序列分为
块,对于每一个整块可以用
来操作(考虑使用
等方法)。而对于一个不完整的块,则考虑暴力修改。
容易证明时间复杂度为:
而这一道题
操作显然可以用
来操作;
而对于
操作,则可以考虑用二分,保证每一次的块都是有序的,那么就可以用
的时间出解。
注意:只有在对于一个不完整块操作时才需要排序。
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,q,block;
struct node{int x,id;} a[1000010];
int u[1000010],belong[1000010],lazy[10010],l[10010],r[10010];
bool cmp(node x,node y)
{
return x.x>y.x;
}
void work(int x,int y,int z)
{
if(belong[x]==belong[y])
{
for(int i=x;i<=y;i++)
a[u[i]].x+=z;
sort(a+l[belong[x]],a+r[belong[x]]+1,cmp);
for(int i=l[belong[x]];i<=r[belong[x]];i++)
u[a[i].id]=i;
}
else
{
for(int i=x;belong[i]==belong[x];i++)
a[u[i]].x+=z;
for(int i=y;belong[i]==belong[y];i--)
a[u[i]].x+=z;
sort(a+l[belong[x]],a+r[belong[x]]+1,cmp);
for(int i=l[belong[x]];i<=r[belong[x]];i++)
u[a[i].id]=i;
sort(a+l[belong[y]],a+r[belong[y]]+1,cmp);
for(int i=l[belong[y]];i<=r[belong[y]];i++)
u[a[i].id]=i;
for(int i=belong[x]+1;i<=belong[y]-1;i++)
lazy[i]+=z;
}
}
int solve(int x,int y,int z)
{
int ans=0;
if(belong[x]==belong[y])
{
z-=lazy[belong[x]];
for(int i=x;i<=y;i++)
if(a[u[i]].x>=z) ans++;
}
else
{
for(int i=x;belong[i]==belong[x];i++)
if(a[u[i]].x+lazy[belong[x]]>=z) ans++;
for(int i=y;belong[i]==belong[y];i--)
if(a[u[i]].x+lazy[belong[y]]>=z) ans++;
for(int i=belong[x]+1;i<=belong[y]-1;i++)
{
int L=l[i],R=r[i],MID,O=l[i]-1;
while(L<=R)
{
MID=(L+R)>>1;
if(a[MID].x>=z-lazy[i]) L=MID+1,O=MID; else R=MID-1;
}
ans+=O-l[i]+1;
}
}
return ans;
}
int main()
{
int x,y,z;
char s[5];
scanf("%d %d",&n,&q);
block=sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i].id=i;
belong[i]=i/block+1;
if(belong[i]!=belong[i-1]) l[belong[i]]=i,r[belong[i-1]]=i-1;
}
r[belong[n]]=n;
for(int i=1;i<=belong[n];i++)
sort(a+l[i],a+r[i]+1,cmp);
for(int i=1;i<=n;i++)
u[a[i].id]=i;
for(int i=1;i<=q;i++)
{
scanf("%s %d %d %d",s+1,&x,&y,&z);
if(x>y) swap(x,y);
if(s[1]=='M') work(x,y,z); else printf("%d\n",solve(x,y,z));
}
}