BZOJ 3343 教主的魔法

Posted on 2016-03-24 15:40  ziliuziliu  阅读(189)  评论(0编辑  收藏  举报

第一次写分块。黄学长的模板好漂亮。

由于既要保存原始的位置关系,又要有分块的排序,所以开两个数组。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 1005000
using namespace std;
long long n,q,a[maxn],b[maxn],x,y,z,block,pos[maxn],cnt,add[maxn];
char type[5];
void reset(long long x)
{
    long long l=(x-1)*block+1,r=min(x*block,n);
    for (long long i=l;i<=r;i++)
        b[i]=a[i];
    sort(b+l,b+r+1);
}
void modify(long long x,long long y,long long z)
{
    if (pos[x]==pos[y])
    {
        for (long long i=x;i<=y;i++)
            a[i]+=z;
    }
    else
    {
        for (long long i=x;i<=pos[x]*block;i++)
            a[i]+=z;
        for (long long i=(pos[y]-1)*block+1;i<=y;i++)
            a[i]+=z;
        for (long long i=pos[x]+1;i<=pos[y]-1;i++)
            add[i]+=z;
    }
    reset(pos[x]);reset(pos[y]);
}
long long find(long long x,long long r)
{
    long long left=(x-1)*block+1,right=min(x*block,n),last=right;
    while (left<=right)
    {
        long long mid=(left+right)>>1;
        if (b[mid]<r) left=mid+1;
        else right=mid-1;
    }
    return last-left+1;
}
long long ask(long long x,long long y,long long z)
{
    long long sum=0;
    if (pos[x]==pos[y])
    {
        for (long long i=x;i<=y;i++)
            if (a[i]+add[pos[i]]>=z) sum++;
        return sum;
    }
    else
    {
        for (long long i=x;i<=pos[x]*block;i++)
            if (a[i]+add[pos[i]]>=z) sum++;
        for (long long i=(pos[y]-1)*block+1;i<=y;i++)
            if (a[i]+add[pos[i]]>=z) sum++;
        for (long long i=pos[x]+1;i<=pos[y]-1;i++)
            sum=sum+find(i,z-add[i]);
        return sum;
    }
}
int main()
{
    scanf("%lld%lld",&n,&q);
    block=sqrt(n);
    for (long long i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        if (i%block==0) pos[i]=i/block;
        else pos[i]=i/block+1;
    }
    cnt=pos[n];
    for (long long i=1;i<=cnt;i++)
        reset(i);
    for (long long i=1;i<=q;i++)
    {
        scanf("%s%lld%lld%lld",type,&x,&y,&z);
        if (type[0]=='M') modify(x,y,z);
        else printf("%lld\n",ask(x,y,z));
    }
    return 0;
}