链接
http://www.lydsy.com/JudgeOnline/problem.php?id=3809
题解
这样搞,我们把序列分块,每一块有个标记表示这个块被整体加了几。
每次查询,对于完整的块,我们提前把里面的元素排好序,每次只要二分一下就好了。
修改,完整的块,直接打标记即可;对于前后那些零散的,暴力修改之后,把这个块重新拍下序。
代码
//分块
#include <cstdio>
#include <algorithm>
#define maxn 1100000
#define maxs 2048
using namespace std;
int N, Q, a[maxn], tag[maxs], tmp[maxn], size;
inline int read(int x=0)
{
char c=getchar();
while(c<48 or c>57)c=getchar();
while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48, c=getchar();
return x;
}
inline char readc()
{
char c=getchar();
while(c^'A' and c^'M')c=getchar();
return c;
}
inline void init()
{
int i, l, r;
N=read(), Q=read();
for(i=1;i<=N;i++)tmp[i]=a[i]=read();
for(size=1;(1<<size)*(1<<size)<=N;size++);size--;
for(i=0;i<=N>>size;i++)
{
l=i<<size, r=(i+1<<size)-1;
sort(tmp+l,tmp+r+1);
}
}
inline void pushdown(int block)
{
int l=block<<size, r=(block+1<<size)-1, i;
for(i=l;i<=r;i++)a[i]+=tag[block], tmp[i]+=tag[block];
tag[block]=0;
}
inline void rebuild(int block)
{
int l=block<<size, r=(block+1<<size)-1, i;
for(i=l;i<=r;i++)tmp[i]=a[i];
sort(tmp+l,tmp+r+1);
}
inline void add(int l, int r, int w)
{
int i;
for(i=(l>>size)+1;i<r>>size;i++)tag[i]+=w;
pushdown(l>>size), pushdown(r>>size);
for(i=l;i>>size==l>>size and i<=r;i++)a[i]+=w;
if((l>>size)^(r>>size))for(i=r;i>>size==r>>size;i--)a[i]+=w;
rebuild(l>>size);if((l>>size)^(r>>size))rebuild(r>>size);
}
inline int bin(int block, int w)
{
int l, r, mid;
l=block<<size, r=(block+1<<size)-1;
if(tmp[r]<w)return 0;
while(l^r)
{
mid=(l+r)>>1;
if(tmp[mid]>=w)r=mid;
else l=mid+1;
}
return (block+1<<size)-1 - l + 1;
}
inline void quiry(int l, int r, int c)
{
int i, ans=0;
for(i=(l>>size)+1;i<r>>size;i++)ans+=bin(i,c-tag[i]);
pushdown(l>>size), pushdown(r>>size);
for(i=l;i>>size==l>>size and i<=r;i++)if(a[i]>=c)ans++;
if((l>>size)^(r>>size))for(i=r;i>>size==r>>size;i--)if(a[i]>=c)ans++;
printf("%d\n",ans);
}
int main()
{
char type;
int l, r, x;
init();
for(int i=1;i<=Q;i++)
{
type=readc();
l=read(), r=read(), x=read();
if(type=='M')add(l,r,x);
else quiry(l,r,x);
}
return 0;
}