ZOJ 2112 分块+二分

版权声明:存在错误或者不清楚的地方还望指出 https://blog.csdn.net/hypHuangYanPing/article/details/82860680
/**
链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112
区间第k大+单点修改 
对于每块进行排序,二分确定区间第k大的数;
对于单点修改,修改当前的值,并且对当前块的值进行重新排序;
时间消耗比较大;
对于主席树的解法相对来说比较耗费空间
*/

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn=1e5+7;
int n,blo,q,pos[maxn];

vector<int>vec[maxn];

int a[maxn],k;

bool judge(int l,int r,int x){
    int cnt=0;
    for(int i=l;i<=min(r,pos[l]*blo);i++) if(x>a[i]) cnt++;
    if(pos[l]!=pos[r]){
        for(int i=(pos[r]-1)*blo+1;i<=r;i++) if(x>a[i]) cnt++;
    }
    for(int i=pos[l]+1;i<=pos[r]-1;i++) cnt+=lower_bound(vec[i].begin(),vec[i].end(),x)-vec[i].begin();
    return cnt>=k;
}

int main (){
    int t;scanf("%d",&t);
    while(t--){
       for(int i=1;i<maxn;i++) vec[i].clear();
       scanf("%d %d",&n,&q);
       for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
       blo=sqrt(n);
       for(int i=1;i<=n;i++) pos[i]=(i-1)/blo+1;
       for(int i=1;i<=n;i++) vec[pos[i]].push_back(a[i]);
       for(int i=1;i<=pos[n];i++) sort(vec[i].begin(),vec[i].end());

       char ch[3];
       while(q--){
          scanf("%s",ch);
          if(ch[0]=='Q'){
             int l,r;scanf("%d %d %d",&l,&r,&k);
             int L=1,R=1e9+7,mid;//二分查找当前区间[l,r]第k大的数字;
             while(R-L>1){
                mid=(R+L)/2;
                if(judge(l,r,mid)) R=mid;
                else L=mid;
             }
             printf("%d\n",L);
          }
          else {
             int id,val;scanf("%d %d",&id,&val);
             int tmp=pos[id];
             a[id]=val;
             vec[tmp].clear();//单点修改之后,对于当前块内vec的值需要重新进行排序;
             for(int i=(tmp-1)*blo+1;i<=min(n,tmp*blo);i++) vec[tmp].push_back(a[i]);
             sort(vec[tmp].begin(),vec[tmp].end());
          }
       }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hypHuangYanPing/article/details/82860680