UOJ614 【JOISC2021】道路建设
UOJ614 【JOISC2021】道路建设
\(\rm KDT\)
曼哈顿距离\(k\)近点对?看起来十分神仙的样子。
但是!我们都会乱搞!
听起来好像有点像Luogu4357[CQOI2016]K 远点对,但是\(k\)比较大,我们可以试一试。
对于所有点建\(\rm KDT\),然后维护一个堆,一个点一个点枚举,如果堆顶元素小于等于当前节点到询问矩形中可能的最短距离,停止搜索。注意需要去除一个点与自己匹配的贡献。
在\(\rm KDT\)中查询的时候,一个点到一个矩形的最短距离不再是这个点到矩形四个顶点的最短距离,而是各维度坐标到矩形对应维度边界的绝对值差的最小值之和。
由于询问为无序点对,我们可以在堆中存储\(2k\)个有序点对的距离,输出时隔一个数依次选取\(k\)个距离即为答案。
然后我们就草率地通过了这道题,不会有人hack我吧不会吧不会吧。
\(Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#define N 250005
#define ll long long
using namespace std;
int n,k;
ll ans[N];
struct Point
{
int x,y;
Point () {}
Point (int xx,int yy):x(xx),y(yy) {}
}a[N];
ll dis(Point A,Point B)
{
return (ll)abs(A.x-B.x)+abs(A.y-B.y);
}
priority_queue<ll>q;
bool cmpX(const Point &A,const Point &B)
{
return A.x<B.x;
}
bool cmpY(const Point &A,const Point &B)
{
return A.y<B.y;
}
struct node
{
int xl,xr,yl,yr;
}tr[N << 2];
void build(int p,int l,int r,bool opt)
{
if (l==r)
{
tr[p].xl=tr[p].xr=a[l].x;
tr[p].yl=tr[p].yr=a[l].y;
return;
}
int mid(l+r >> 1);
nth_element(a+l,a+mid,a+r+1,(!opt)?cmpX:cmpY);
build(p << 1,l,mid,!opt),build(p << 1 | 1,mid+1,r,!opt);
tr[p].xl=min(tr[p << 1].xl,tr[p << 1 | 1].xl);
tr[p].xr=max(tr[p << 1].xr,tr[p << 1 | 1].xr);
tr[p].yl=min(tr[p << 1].yl,tr[p << 1 | 1].yl);
tr[p].yr=max(tr[p << 1].yr,tr[p << 1 | 1].yr);
}
void ckmax(int &x,int y)
{
x=(x>y)?x:y;
}
void calc(int p,int l,int r,int x)
{
if (q.size()==k)
{
ll D=0;
if (tr[p].xl>a[x].x || tr[p].xr<a[x].x)
D+=min(abs(a[x].x-tr[p].xl),abs(a[x].x-tr[p].xr));
if (tr[p].yl>a[x].y || tr[p].yr<a[x].y)
D+=min(abs(a[x].y-tr[p].yl),abs(a[x].y-tr[p].yr));
if (D>=q.top())
return;
}
if (l==r)
{
ll D=dis(a[x],Point(tr[p].xl,tr[p].yl));
if (!D)
return;
if (q.size()==k)
q.pop();
q.push(D);
return;
}
int mid(l+r >> 1);
calc(p << 1,l,mid,x);
calc(p << 1 | 1,mid+1,r,x);
}
int main()
{
scanf("%d%d",&n,&k);
k=k << 1;
for (int i=1;i<=n;++i)
scanf("%d%d",&a[i].x,&a[i].y);
build(1,1,n,0);
for (int i=1;i<=n;++i)
calc(1,1,n,i);
for (int i=1;i<=(k >> 1);++i)
ans[i]=q.top(),q.pop(),q.pop();
for (int i=(k >> 1);i;--i)
printf("%lld\n",ans[i]);
return 0;
}