BZOJ1901 Dynamic Rankings 分块+二分法

题意:给定一个数列,维护:1、单点修改  2、查询区间第k大

题解:

找个代码debug网上全是树套树。

然而还是喜欢这么写分块,开个结构体什么的看起来很一目了然不是吗……

先把每个块排序

修改:二分找到修改的位置在块中的位置,然后移动到修改后应该在的块中的位置。

查询:确定上下界后二分答案,看每个答案有多少个数小于它代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXS=250+2;
struct BLOCK{
    int a[MAXS],b[MAXS];
}block[MAXS];
int N,M,S,T,U,L=INT_MAX;
char s;

void Build(int &S,int N){
    S=ceil(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);
            L=min(L,block[k].b[1]-1),U=max(U,block[k].b[j]+1);
            k++,j=0;
        }
    }
}

void Update(int x,int t){
    int p=(x%S?x/S+1:x/S),m=(1+S)>>1;
    x-=(p-1)*S;

    for(int l=1,r=S;l<r;m=(l+r)>>1)
        if(block[p].b[m]<block[p].a[x]) l=m+1;
        else r=m;
    block[p].b[m]=t;
    while(block[p].b[m]<block[p].b[m-1] && m!=1) swap(block[p].b[m],block[p].b[m-1]),m--;
    while(block[p].b[m]>block[p].b[m+1] && m!=S) swap(block[p].b[m],block[p].b[m+1]),m++;

    block[p].a[x]=t,U=max(U,t-1),L=min(L,t-1);
}

int Find(int x,int y,int k){
    int ret=0,s=ceil((double)x/S),t=ceil((double)y/S);
    for(int i=s;i<=t;i++){
        if(i==s){
            int n=(s==t?y-(t-1)*S:S);
            for(int j=x-(s-1)*S;j<=n;j++)
                ret+=(block[i].a[j]<k);
        }
        else if(i==t && y%S)
            for(int j=1;j<=y-(t-1)*S;j++)
                ret+=(block[i].a[j]<k);
        else{
            int l=1,r=S,m;
            while(l!=r){
                m=(l+r)>>1;
                if(block[i].b[m]>=k) r=m;
                else l=m+1;
            }
            if(block[i].b[l]>=k) --l;
            ret+=l;
        }
    }
    return ret;
}

int Query(int x,int y,int k){
    int m,l=L,r=U;
    while(l!=r){
        m=(l+r)>>1;
        if(Find(x,y,m)>=k) r=m;
        else l=m+1;
    }
    return l-1;
}

int main(){
    cin >> N >> M;
    Build(S,N);
    N=(N%S?N/S+1:N/S);

    for(int i=1,l,r,x;i<=M;i++){
        cin >> s;
        cin >> l >> r;
        if(s=='C') Update(l,r);
        if(s=='Q'){
            cin >> x;
            cout << Query(l,r,x) << endl;
        }
    }

    return 0;
}
View Code

 

posted @ 2017-02-27 00:23  WDZRMPCBIT  阅读(145)  评论(0编辑  收藏  举报