ZOJ 2112 分块+二分

/**
链接: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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值