【题解】[JOISC 2021 Day1]道路の建設案
这应该是 JOISC2021 最简单的一题了。
求前 $k $ 大的曼哈顿距离,先考虑求第 \(k\) 大的距离。
第 \(k\) 大的距离,比较套路的做法是二分答案,然后计算距离 \(\le dis\) 的点对数。
曼哈顿距离不好求,考虑转化为切比雪夫距离,原来的点 \((x,y)\to (x+y,x-y)\) 。
那么这就是一个经典的二维数点问题。
同时我们不需要真正数有多少点对,点对数 \(\ge k\) 时直接返回即可。
所以具体操作是对所有点按 \(x\) 坐标排序,用队列维护 \(x\) 坐标在 \(dis\) 范围内的点,同时用 set
维护队列中的点的 \(y\) 坐标。
值域为 \(S\) ,则时间复杂度为 \(\mathcal{O}((n+k)\log n\log S+k\log k)\) 。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 250005
#define inf 0x3f3f3f3f3f3f3f3fLL
#define int long long
using namespace std;
int n,k;
typedef pair<int,int> Pr;
#define X first
#define Y second
set<Pr>s;queue<Pr>q;Pr a[N];
int ans[N],T;
bool check(int dis){
T=0;s.clear();
while(!q.empty())q.pop();
rep(i,1,n){
while(!q.empty()&&q.front().X+dis<a[i].X)s.erase(make_pair(q.front().Y,q.front().X)),q.pop();
set<Pr>::iterator it=s.lower_bound(make_pair(a[i].Y-dis,-inf));
while(it!=s.end()&&(*it).X<=dis+a[i].Y){
ans[++T]=max(abs((*it).X-a[i].Y),a[i].X-(*it).Y);
it++;if(T>=k)return true;
}
s.insert(make_pair(a[i].Y,a[i].X));q.push(make_pair(a[i].X,a[i].Y));
}
return false;
}
signed main(){
scanf("%lld%lld",&n,&k);
rep(i,1,n){
int x,y;scanf("%lld%lld",&x,&y);
a[i].X=x+y;a[i].Y=x-y;
}
sort(a+1,a+n+1);puts("No Copy");
int l=1,r=4000000000,ed=0;
while(l<=r){
int mid=(0LL+l+r)>>1;
if(check(mid))ed=mid,r=mid-1;
else l=mid+1;
}
check(ed-1);
sort(ans+1,ans+T+1);
rep(i,1,T)printf("%lld\n",ans[i]);
rep(i,1,k-T)printf("%lld\n",ed);
return 0;
}