天天看點

[bzoj 3343]教主的魔法

教主最近學會了一種神奇的魔法,能夠使人長高。于是他準備示範給XMYZ資訊組每個英雄看。于是N個英雄們又一次聚集在了一起,這次他們排成了一列,被編号為1、2、……、N。

每個人的身高一開始都是不超過1000的正整數。教主的魔法每次可以把閉區間[L,R](1≤L≤R≤N)内的英雄的身高全部加上一個整數W。(雖然L=R時并不符合區間的書寫規範,但我們可以認為是單獨增加第L(R)個英雄的身高)

CYZ、光哥和ZJQ等人不信教主的邪,于是他們有時候會問WD閉區間 [L, R] 内有多少英雄身高大于等于C,以驗證教主的魔法是否真的有效。

WD巨懶,于是他把這個回答的任務交給了你。

這道題是一道不錯的分塊題。首先單考慮詢問,由于是問是否大于等于某值,可以先将各個塊給排序,然後二分,頭尾兩個不完整塊要暴力枚舉,之後修改,給整塊打上加法标記,不完整塊要暴力修改,由于這樣可能會破壞不完整塊所在的塊的單調性,是以要重新排序。那麼這道題就解決了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m;
int a[],b[],belong[],bl[],br[],add[];
void ps(int x)
{
    int l=bl[x],r=br[x];
    for(int i=l;i<=r;i++)b[i]=a[i];
    sort(b+l,b+r+);
}
void fk()
{
    int cnt=*sqrt(n);
    for(int i=;i<=n;i++)
    {
        int bg=(i-)/cnt+;
        belong[i]=bg;
        if(bl[bg]==)bl[bg]=i,br[bg-]=i-;
    }
    br[belong[n]]=n;
}
int ef(int x,int w)
{
    int l=bl[x],r=br[x],ans=bl[x]-;
    while(l<=r)
    {
        int mid=(l+r)/;
        if(b[mid]<w)
        {
            l=mid+;
            ans=mid;
        }
        else r=mid-;
    }
    return br[x]-ans;
}
void solve1(int l,int r,int c)
{
    int lg=belong[l],rg=belong[r];
    if(lg==rg)
    {
        for(int i=l;i<=r;i++)a[i]+=c;
        ps(lg);
        return ;
    }
    for(int i=l;i<=br[lg];i++)a[i]+=c;ps(lg);
    for(int i=bl[rg];i<=r;i++)a[i]+=c;ps(rg);
    for(int i=lg+;i<=rg-;i++)add[i]+=c;
}
int solve2(int l,int r,int c)
{
    int s=;int lg=belong[l],rg=belong[r];
    if(lg==rg)
    {
        for(int i=l;i<=r;i++)
        {
            if(a[i]+add[lg]>=c)s++;
        }
        return s;
    }
    for(int i=l;i<=br[lg];i++)
    {
        if(a[i]+add[lg]>=c)s++;
    }
    for(int i=bl[rg];i<=r;i++)
    {
        if(a[i]+add[rg]>=c)s++;
    }
    for(int i=lg+;i<=rg-;i++)s+=ef(i,c-add[i]);
    return s;
}
char s1[];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=;i<=n;i++)scanf("%d",&a[i]);
    fk();
    for(int i=;i<=belong[n];i++)ps(i);
    for(int i=;i<=m;i++)
    {
        int x,y,c;
        scanf("%s%d%d%d",s1+,&x,&y,&c);
        if(s1[]=='M')solve1(x,y,c);
        else printf("%d\n",solve2(x,y,c));
    }
    return ;
}