1. 程式人生 > 其它 >【題解】[JOISC 2021 Day1]道路の建設案

【題解】[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;
}