Loading

【题解】[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;
} 
posted @ 2021-10-04 17:10  7KByte  阅读(53)  评论(0编辑  收藏  举报