[bzoj] 3343 教主的魔法 || 带修改分块

原题

长度为n的序列,有两种操作:
1、[l,r]区间每个数+w
2、询问[l,r]区间有多少个数>c


记录lazy数组即可。

#include<cstdio>
#include<algorithm>
#define N 1000010
#define B 1010
#define st(x) (((x)-1)*B+1)
#define ed(x) min((x)*B,n)
#define bel(x) (((x)-1)/B+1)
using namespace std;
int n,q,l,r,w,a[N],s[N],lz[N];
char b[3];

int read()
{
    int ans=0,fu=1;
    char j=getchar();
    for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
    for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
    return ans*fu;
}

void push(int x)
{
    if (!lz[x]) return ;
    for (int i=st(x);i<=ed(x);i++)
	s[i]+=lz[x],a[i]+=lz[x];
    lz[x]=0;
}

void single_change(int l,int r,int w)
{
    int b=bel(l);
    push(b);
    for (int i=l;i<=r;i++) a[i]+=w;
    for (int i=st(b);i<=ed(b);i++) s[i]=a[i];
    sort(s+st(b),s+ed(b)+1);
}

void change(int l,int r,int w)
{
    if (bel(l)==bel(r)) return single_change(l,r,w);
    for (int i=bel(l)+1;i<bel(r);i++)
	lz[i]+=w;
    single_change(l,ed(bel(l)),w);
    single_change(st(bel(r)),r,w);
}

int block_query(int b,int w)
{
    return s+ed(b)-upper_bound(s+st(b),s+ed(b)+1,w-lz[b]-1)+1;
}

int single_query(int l,int r,int w)
{
    int b=bel(l),ret=0;
    for (int i=l;i<=r;i++)
	if (a[i]+lz[b]>=w) ret++;
    return ret;
}

int query(int l,int r,int w)
{
    if (bel(l)==bel(r)) return single_query(l,r,w);
    int ret=0;
    for (int i=bel(l)+1;i<bel(r);i++)
	ret+=block_query(i,w);
    return ret+single_query(l,ed(bel(l)),w)+single_query(st(bel(r)),r,w);
}

int main()
{
    n=read();
    q=read();
    for (int i=1;i<=n;i++)
	a[i]=s[i]=read();
    for (int i=1;st(i)<=n;i++) sort(s+st(i),s+ed(i)+1);
    while (q--)
    {
	scanf("%s",b);
	l=read();
	r=read();
	w=read();
	if (b[0]=='M') change(l,r,w);
	else printf("%d\n",query(l,r,w));
    }
    return 0;
}
posted @ 2018-01-03 20:21  Mrha  阅读(158)  评论(0编辑  收藏  举报