分塊二分——BZO3343 教主的魔法

題面:BZOJ3343
分塊二分大暴力!
以前初三剛學分塊的時候以爲這題很難QAQ,現在認爲……
這題實在是water到不知道哪裏去了666
我們對於數據分塊,然後對塊內的數進行排序
修改的時候發現如果整個塊都被覆蓋在區間裏面的話,那麼就對整個塊進行標記(因爲整個塊內的數都被加上了)
兩邊多出來的暴力修改,然後再次對塊內進行排序
排序的原因是詢問時要對塊進行二分
詢問還是老辦法,對於一整個塊的數據我們二分找比要求的數大的個數(這就是排序的原因),對於多出來的暴力統計
時間複雜度大約是O(Qnlogn)

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <ctime>
#include <map>
#include <queue>
#include <cstdlib>
#include <string>
#include <climits>
#include <set>
#include <vector>
using namespace std;
inline int read(){
    int k=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
    return k*f;
}
inline void write(int x){
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writeln(int x){
    write(x);puts("");
}
int n,m,c,p,a[1000001],w[1000001]={0},b[1000001]={0},sum[1000001]={0};
inline void yu(int x){
    int l=(x-1)*p+1,r=min(n,x*p);
    for(int i=l;i<=r;i++)b[i]=a[i];
    sort(b+l,b+r+1);
}
inline void add(int x,int y,int z){
    if(w[x]==w[y])for(int i=x;i<=y;i++)a[i]+=z;
    else{
        for(int i=x;i<=w[x]*p;i++)a[i]+=z;
        for(int i=(w[y]-1)*p+1;i<=y;i++)a[i]+=z;
    }
    yu(w[x]);yu(w[y]);
    for(int i=w[x]+1;i<w[y];i++)sum[i]+=z;
}
inline int erfen(int x,int v){
    int l=(x-1)*p+1,r=min(n,x*p);int la=r;
    while(l<=r){
        int mm=(l+r)/2;
        if(b[mm]<v)l=mm+1;
        else r=mm-1;
    }
    return la-l+1;
}
inline int ssum(int x,int y,int z){
    int ans=0;
    if(w[x]==w[y]){for(int i=x;i<=y;i++)if(a[i]+sum[w[i]]>=z)ans++;}
    else{
        for(int i=x;i<=w[x]*p;i++)if(a[i]+sum[w[i]]>=z)ans++;
        for(int i=(w[y]-1)*p+1;i<=y;i++)if(a[i]+sum[w[i]]>=z)ans++;
    }
    for(int i=w[x]+1;i<w[y];i++)ans+=erfen(i,z-sum[i]);
    return ans;
}
int main()
{
    n=read();c=read();
    p=(int)(sqrt(n));
    for(int i=1;i<=n;i++){
        a[i]=read();
        w[i]=(i-1)/p+1;
        b[i]=a[i];
    }
    if(n%p==0)m=n/p;
    else m=n/p+1;
    for(int i=1;i<=m;i++)yu(i);
    for(int i=1;i<=c;i++){
        char ss[5];scanf("%s",ss);int x=read(),y=read(),z=read();
        if(ss[0]=='M')add(x,y,z);
        else writeln(ssum(x,y,z));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章