BZOJ 3343: 教主的魔法

Description

教主最近學會了一種神奇的魔法,能夠使人長高。於是他準備演示給XMYZ信息組每個英雄看。於是N個英雄們又一次聚集在了一起,這次他們排成了一列,被編號爲1、2、……、N。
每個人的身高一開始都是不超過1000的正整數。教主的魔法每次可以把閉區間[L, R](1≤L≤R≤N)內的英雄的身高全部加上一個整數W。(雖然L=R時並不符合區間的書寫規範,但我們可以認爲是單獨增加第L(R)個英雄的身高)
CYZ、光哥和ZJQ等人不信教主的邪,於是他們有時候會問WD閉區間 [L, R] 內有多少英雄身高大於等於C,以驗證教主的魔法是否真的有效。
WD巨懶,於是他把這個回答的任務交給了你。

Input

   第1行爲兩個整數N、Q。Q爲問題數與教主的施法數總和。
   第2行有N個正整數,第i個數代表第i個英雄的身高。
   第3到第Q+2行每行有一個操作:

(1) 若第一個字母爲“M”,則緊接着有三個數字L、R、W。表示對閉區間 [L, R] 內所有英雄的身高加上W。
(2) 若第一個字母爲“A”,則緊接着有三個數字L、R、C。詢問閉區間 [L, R] 內有多少英雄的身高大於等於C。

Output

   對每個“A”詢問輸出一行,僅含一個整數,表示閉區間 [L, R] 內身高大於等於C的英雄數。

Sample Input

5 3

1 2 3 4 5

A 1 5 4

M 3 5 1

A 1 5 4

Sample Output

2

3

HINT

【輸入輸出樣例說明】

原先5個英雄身高爲1、2、3、4、5,此時[1, 5]間有2個英雄的身高大於等於4。教主施法後變爲1、2、4、5、6,此時[1, 5]間有3個英雄的身高大於等於4。

【數據範圍】

對30%的數據,N≤1000,Q≤1000。

對100%的數據,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000。

Solution
分塊可以做,然而花式分塊更快。。
在每個操作的端點處劃分,共分爲最多4Q塊,那麼每個操作必會在一段連續塊上
處理每塊時,遍歷所有包含它的操作,若爲修改,則delta+=w,若爲查詢,則記錄c-delta,然後將詢問按c-delta排序
之後遍歷該塊中的數,二分+差分維護貢獻
時間複雜度 這裏寫圖片描述

Code

#include<bits/stdc++.h>

typedef unsigned char uchar;
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;

#define xx first
#define yy second

template<typename T> inline T max(T a,T b){return a>b?a:b;}
template<typename T> inline T min(T a,T b){return a<b?a:b;}
template<typename T> inline T abs(T a){return a>0?a:-a;}
template<typename T> inline void repr(T &a,T b){if(a<b)a=b;}
template<typename T> inline void repl(T &a,T b){if(a>b)a=b;}
template<typename T> T gcd(T a,T b){if(b)return gcd(b,a%b);return a;}
#define mp(a,b) std::make_pair(a,b)
#define pb push_back
#define lb(x) ((x)&(-(x)))
#define sqr(x) ((x)*(x))
#define pm(a,b,c,d) a=(a+(ll)(b)*(c))%(d)

int n,m,h[1000001],q[3000][4],bl[12010],ans[3000],tmp[3000];

struct yjq
{
    int x,id;
    inline bool operator <(const yjq &p)const
    {
        return x<p.x;
    }
}f[3000];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        scanf("%d",h+i);
    int bc=2;
    bl[0]=n-1;
    bl[1]=-1;
    for(int i=0;i<m;i++)
    {
        char opt[2];
        scanf("%s%d%d%d",opt,&q[i][1],&q[i][2],&q[i][3]);
        q[i][1]--,q[i][2]--;
        q[i][0]=opt[0]=='A';
        bl[bc++]=q[i][1]-1;
        bl[bc++]=q[i][2];
    }
    std::sort(bl,bl+bc);
    bc=std::unique(bl,bl+bc)-bl;
    for(int i=1;i<bc;i++)
    {
        bl[i-1]++;
        int delta=0,fm=0;
        for(int j=0;j<m;j++)
            if(q[j][1]<=bl[i-1]&&q[j][2]>=bl[i])
            {
                if(q[j][0]==0)
                    delta+=q[j][3];
                else
                    f[fm].x=q[j][3]-delta,f[fm++].id=j;
            }
        std::sort(f,f+fm);
        memset(tmp,0,sizeof(tmp));
        for(int j=bl[i-1];j<=bl[i];j++)
        {
            if(f[0].x>h[j])continue;
            int l=0,r=fm;
            while(r-l>1)
            {
                if(f[(l+r)>>1].x>h[j])
                    r=(l+r)>>1;
                else
                    l=(l+r)>>1;
            }
            tmp[l]++;
        }
        for(int j=fm-1,t=0;j>=0;j--)
        {
            t+=tmp[j];
            ans[f[j].id]+=t;
        }
    }
    for(int i=0;i<m;i++)
        if(q[i][0]==1)
            printf("%d\n",ans[i]);
}

link to my blog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章