Atcoder 364 D - K-th Nearest

Problem Statement

There are N+Q points A1,…,AN,B1,…,BQA1​,…,AN​,B1​,…,BQ​ on a number line, where point Ai has a coordinate ai​ and point Bj has a coordinate bj.

For each j=1,2,…,Q, answer the following question:

  • Let X be the point among A1​,A2​,…,AN​ that is the kj-th closest to point Bj. Find the distance between points X and Bj​. More formally, let didi​ be the distance between points Ai​ and Bj​. Sort (d1,d2,…,dN) in ascending order to get the sequence (d1′,d2′,…,dN′). Find dkj′​.

Constraints

  • 1≤N,Q≤105
  • −108≤ai,bj≤108
  • 1≤kj≤N
  • All input values are integers.

Input

The input is given from Standard Input in the following format:

N Q
a1 a2​ …… aN​
b1​ k1
b2 k2​
⋮
bQ kQ

Output

Print Q lines. The l-th line (1≤l≤Q) should contain the answer to the question for j=l as an integer.

 

Sample Input 1Copy

Copy

4 3
-3 -1 5 6
-2 3
2 1
10 4

Sample Output 1Copy

Copy

7
3
13

Let us explain the first query.

The distances from points A1,A2,A3,A4​ to point B1​ are 1,1,7,8 respectively, so the 3rd closest to point B1​ is point A3​. Therefore, print the distance between point A3​ and point B1​, which is 7.

原题链接:

https://atcoder.jp/contests/abc364/tasks/abc364_d 

 

题干大意:

相当于一共Q次查询,每次查询给你一个点B和k,要求你求出距离点B,距离第k近的点距离B点的距离,这道题目是一道二分答案, 假设答案为D,则在A中,区间[B-D,B+D] 中点的个数应该大于等于k,距离变大,区间变大,区间内点的个数不会减少,这样具有单调性的问题,可以使用二分去做,至于计算区间[B-D,B+D]中点的个数,使用二分去计算,  

l=b[i]+mid; r=b[i]-mid;
cnt=upper_bound(A.begin(),A.end(),r)-lower_bound(A.begin(),A.end(),l);

为什么这样就可以计算出区间内点的个数了呢?假设B-D 对应的下标为p1, B+D 对应的下标为p2, 则区间中点的个数为p2-p1+1, lower_bound 计算的是区间内大于等于l的第一个数的下标,而upper_bound计算的是第一个大于r的数的下标,第一个大于r,的下标是p2+1,因此正好求得的cnt是区间内点的个数
如果check后满足,即cnt>=k ,证明这个距离长度是符合的,更新上界为mid, 如果不满足,我们就需要扩大区间,扩大距离,更新lo=mid+1 


代码实现:

#include<bits/stdc++.h>

using i64=long long;

void solve()
{
    int N,Q;
    std::cin>>N>>Q;
    std::vector<int> A(N);
    std::vector<int> B(Q),k(Q);
    for(int i=0;i<N;i++)
    {
        std::cin>>A[i];
    }
    for(int i=0;i<Q;i++)
    {
        std::cin>>B[i];
        std::cin>>k[i];
    }
    sort(A.begin(),A.end());
    for(int i=0;i<Q;i++)
    {
        int lo=0; int hi=2E8;
        while(lo<hi)
        {
            int mid=(lo+hi)/2;
            int l=B[i]-mid;
            int r=B[i]+mid;
            int cnt=upper_bound(A.begin(),A.end(),r)-lower_bound(A.begin(),A.end(),l);
            if(cnt>=k[i])
            {
                hi=mid;
            }
            else lo=mid+1;
        }
        std::cout<<lo<<"\n";
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t=1;
    while(t--)
    {
        solve();
    }
    return 0;
}


 

  • 25
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值