版权声明:本文为蒟蒻原创文章,转载请注明出处哦~ https://blog.csdn.net/a54665sdgf/article/details/82942423
题目大意:有n个旅馆,每个旅馆有三个参数x,y,c,分别代表旅馆的坐标和需要花的钱。有m个人想住这些旅馆,给你每个人的坐标和钱数,求出每个人能住进的离他最近的旅馆,如果有多个旅馆,则选择下标最小的。
解法:此题属于二维区间的极值查询问题,可以对每个旅馆的x坐标和y坐标轮流二分,建立一棵KD树,然后启发式搜索+剪枝。
#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll linf=0x3f3f3f3f3f3f3f3f;
const int N=2e5+10;
const int M=2e4+10;
struct node
{
ll x[2];
int c,i;
node(ll x0=0,ll x1=0,int c_=0,int i_=0):x(
{
x0,x1
}),c(c_),i(i_) {}
} hotel[N],person[M];
int n,m;
ll mindis;
int index,ansi;
ll dist(const node& a,const node& b)
{
return (a.x[0]-b.x[0])*(a.x[0]-b.x[0])+(a.x[1]-b.x[1])*(a.x[1]-b.x[1]);
}
void build(int l,int r,int dim)
{
if(l>=r)return;
int mid=(l+r)>>1;
nth_element(hotel+l,hotel+mid,hotel+r+1,[dim](const node& a,const node& b)
{
return a.x[dim]<b.x[dim];
});
build(l,mid-1,dim^1);
build(mid+1,r,dim^1);
}
void query(const node& p,int l,int r,int dim)
{
if(l>r)return;
int mid=(l+r)>>1;
ll dis=dist(p,hotel[mid]);
if(hotel[mid].c<=p.c&&(dis<mindis||(dis==mindis&&hotel[mid].i<index)))
{
mindis=dis,index=hotel[mid].i,ansi=mid;
}
if(hotel[mid].x[dim]<p.x[dim])
{
query(p,mid+1,r,dim^1);
if((hotel[mid].x[dim]-p.x[dim])*(hotel[mid].x[dim]-p.x[dim])<mindis)query(p,l,mid-1,dim^1);
}
else
{
query(p,l,mid-1,dim^1);
if((hotel[mid].x[dim]-p.x[dim])*(hotel[mid].x[dim]-p.x[dim])<mindis)query(p,mid+1,r,dim^1);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=0; i<n; ++i)
{
scanf("%lld%lld%d",&hotel[i].x[0],&hotel[i].x[1],&hotel[i].c);
hotel[i].i=i;
}
build(0,n-1,0);
while(m--)
{
mindis=linf;
ll x0,x1;
int c_;
scanf("%lld%lld%d",&x0,&x1,&c_);
query(node(x0,x1,c_,0),0,n-1,0);
printf("%lld %lld %d\n",hotel[ansi].x[0],hotel[ansi].x[1],hotel[ansi].c);
}
}
return 0;
}
ps:由于此题的数据不是很刁钻,因此直接从中间向两边暴搜也可以过。