2019hdu多校 K-th Closest Distance

题目链接:Click here

大致题意:q次询问,每次询问你区间[L,R]中|p-ai|的值第k小的是多少

Solution:

直接找是很困难的,我们考虑二分答案,那么本题就十分简单了

我们对权值维护一颗主席树,每次只要查询区间[L,R]中权值在[p-mid,p+mid]之的数的个数就行了

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int n,m,maxn,lst,L,R,k,p,a[N];
int rt[N],sz[N*40];
int tot,ls[N*40],rs[N*40];
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
void build(int &q,int l,int r){
    q=++tot;sz[q]=0;
    if(l==r) return ;
    int mid=l+r>>1;
    build(ls[q],l,mid);
    build(rs[q],mid+1,r);
}
void ins(int &q,int lst,int l,int r,int x){
    q=++tot;sz[q]=sz[lst]+1;
    ls[q]=ls[lst],rs[q]=rs[lst];
    if(l==r) return ;
    int mid=l+r>>1;
    if(mid>=x) ins(ls[q],ls[lst],l,mid,x);
    else ins(rs[q],rs[lst],mid+1,r,x);
}
int query(int q,int lst,int l,int r,int x,int y){
    if(l>=x&&r<=y) return sz[q]-sz[lst];
    int mid=l+r>>1,re=0;
    if(mid>=x) re+=query(ls[q],ls[lst],l,mid,x,y);
    if(mid<y) re+=query(rs[q],rs[lst],mid+1,r,x,y);
    return re;
}
int check(int x){
    int l=max(0,p-x),r=min(maxn,p+x);
    int v=query(rt[R],rt[L-1],1,maxn,l,r);
    return v>=k;
}
void solve(){
    maxn=lst=tot=0;
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
        maxn=max(maxn,a[i]);
    }build(rt[0],1,maxn);
    for(int i=1;i<=n;i++)
        ins(rt[i],rt[i-1],1,maxn,a[i]);
    for(int i=1;i<=m;i++){
        L=read(),R=read(),p=read(),k=read();
        L^=lst,R^=lst,p^=lst,k^=lst;
        int l=0,r=maxn,re=maxn;
        while(l<=r){
            int mid=l+r>>1;
            if(check(mid)) re=mid,r=mid-1;
            else l=mid+1;
        }printf("%d
",re);lst=re;
    }
}
int main(){
    int t=read();
    while(t--) solve();
    return 0;
}
原文地址:https://www.cnblogs.com/NLDQY/p/11281121.html