首页 > 代码库 > BZOJ3343 教主的魔法 二分法+分块

BZOJ3343 教主的魔法 二分法+分块

题意:给定一个数列,维护:1、[L,R]之间所有的数+=W  2、求[L,R]中大于等于C的数的数量

题解:更新用add标记,头尾俩块暴力重构;查询将每个块排序然后二分找。

技术分享
#include <cmath>#include <ctime>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;const int MAXS=1000+2;struct BLOCK{    int a[MAXS],b[MAXS],add;}block[MAXS];int N,M,S;char s;void Update(int l,int r,int x){    if((l-1)%S){        int p=(l-1)/S+1;        for(int i=l-S*(p-1);i<=S && i<=r-(p-1)*S;i++) block[p].a[i]+=x;        for(int i=1;i<=S;i++) block[p].b[i]=block[p].a[i];        sort(block[p].b+1,block[p].b+S+1);        l=p*S+1;    }    while(l+S-1<=r) block[l/S+1].add+=x,l+=S;    if(r%S){        int p=l/S+1;r-=S*(p-1);        for(int i=1;i<=r;i++) block[p].a[i]+=x;        for(int i=1;i<=S;i++) block[p].b[i]=block[p].a[i];        sort(block[p].b+1,block[p].b+S+1);    }}int Find(int p,int l,int r,int c){    c-=block[p].add;    int m=(l+r)>>1;    while(l<=r){        if(block[p].b[m]<c) l=m+1;        else r=m-1;        m=(l+r)>>1;    }    return S-l+1;}int Query(int l,int r,int c){    int ret=0;    if((l-1)%S){        int p=(l-1)/S+1;        for(int i=l-S*(p-1);i<=r-S*(p-1) && i<=S;i++)            if(block[p].a[i]>=c-block[p].add) ret++;        l=p*S+1;    }    while(l+S-1<=r) ret+=Find(l/S+1,1,S,c),l+=S;    if(r%S){        int p=l/S+1;        for(int i=1;i<=r-S*(p-1);i++)            if(block[p].a[i]>=c-block[p].add) ret++;    }    return ret;}int main(){    memset(block,0X7F,sizeof(block));    block[1].add=0;    cin >> N >> M,S=(int)sqrt(N);    for(int i=1,j=1,k=1;i<=N;i++,j++){        cin >> block[k].a[j],block[k].b[j]=block[k].a[j];        if(j==S || i==N){            sort(block[k].b+1,block[k].b+j+1);            k++,j=0,block[k].add=0;        }    }    N=(N%S?N/S+1:N/S);    for(int i=1,l,r,x;i<=M;i++){        cin >> s;        cin >> l >> r >> x;        if(s==M) Update(l,r,x);        if(s==A) cout << Query(l,r,x) << endl;    }    return 0;}
View Code

 

BZOJ3343 教主的魔法 二分法+分块