BZOJ P3343 教主的魔法【分块】

大则分,分则合。

#include <bits/stdc++.h>
const int Max=1e6+5;
int N,M,S,SNum;char CH[3];
int A[Max],B[Max],Lazy[Max],Block[Max];
using namespace std;
int Find(int X,int V){
    int I,J,K,L=(X-1)*S+1,R=min(X*S,N);K=R;
    while(L<=R){
        int Mid=L+R>>1;
        if(B[Mid]<V){
            L=Mid+1;
        } else {
            R=Mid-1;
        }
    }
    return K-L+1;
}
void Set(int X){
    int I,L=(X-1)*S+1,R=min(X*S,N);
    for(I=L;I<=R;I++){
        B[I]=A[I];
    }sort(B+L,B+R+1);
}
void Update(int X,int Y,int W){
    int I,J,K;
    if(Block[X]==Block[Y]){
        for(I=X;I<=Y;I++){
            A[I]+=W;
        }
        Set(Block[X]);
    } else {
        for(I=X;I<=Block[X]*S;I++){
            A[I]+=W;
        }Set(Block[X]);
        for(I=(Block[Y]-1)*S+1;I<=Y;I++){
            A[I]+=W;
        }Set(Block[Y]);
    }
    for(I=Block[X]+1;I<Block[Y];I++){
        Lazy[I]+=W;
    }
}
int GetAns(int X,int Y,int W){
    int I,J,K,Ans=0;
    if(Block[X]==Block[Y]){
        for(I=X;I<=Y;I++){
            if(A[I]+Lazy[Block[I]]>=W){
                Ans++;
            }
        }
    } else {
        for(I=X;I<=Block[X]*S;I++){
            if(A[I]+Lazy[Block[I]]>=W){
                Ans++;
            }
        }
        for(I=(Block[Y]-1)*S+1;I<=Y;I++){
            if(A[I]+Lazy[Block[I]]>=W){
                Ans++;
            }
        }
    }
    for(I=Block[X]+1;I<Block[Y];I++){
        Ans+=Find(I,W-Lazy[I]);
    }
    return Ans;
}
int main(){
    int I,J,K;
    scanf("%d%d",&N,&M);
    S=sqrt(N);SNum=N/S;
    if(N%S){
        SNum++;
    }
    for(I=1;I<=N;I++){
        scanf("%d",&A[I]);
        Block[I]=(I-1)/S+1;
    }
    for(I=1;I<=SNum;I++){
        Set(I);
    }
    for(I=1;I<=M;I++){  
        int X,Y,W;
        scanf("%s%d%d%d",CH,&X,&Y,&W);
        if(CH[0]=='M'){
            Update(X,Y,W);
        } else {
            printf("%d\n",GetAns(X,Y,W));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/81278508