【22.95%】【hdu 5992】Finding Hotels
Problem Description
There are N hotels all over the world. Each hotel has a location and a price. M guests want to find a hotel with an acceptable price and a minimum distance from their locations. The distances are measured in Euclidean metric.
Input
The first line is the number of test cases. For each test case, the first line contains two integers N (N ≤ 200000) and M (M ≤ 20000). Each of the following N lines describes a hotel with 3 integers x (1 ≤ x ≤ N), y (1 ≤ y ≤ N) and c (1 ≤ c ≤ N), in which x and y are the coordinates of the hotel, c is its price. It is guaranteed that each of the N hotels has distinct x, distinct y, and distinct c. Then each of the following M lines describes the query of a guest with 3 integers x (1 ≤ x ≤ N), y (1 ≤ y ≤ N) and c (1 ≤ c ≤ N), in which x and y are the coordinates of the guest, c is the maximum acceptable price of the guest.
Output
For each guests query, output the hotel that the price is acceptable and is nearest to the guests location. If there are multiple hotels with acceptable prices and minimum distances, output the first one.
Sample Input
2
3 3
1 1 1
3 2 3
2 3 2
2 2 1
2 2 2
2 2 3
5 5
1 4 4
2 1 2
4 5 3
5 2 1
3 3 5
3 3 1
3 3 2
3 3 3
3 3 4
3 3 5
Sample Output
1 1 1
2 3 2
3 2 3
5 2 1
2 1 2
2 1 2
1 4 4
3 3 5
Source
2016ACM/ICPC亚洲区青岛站-重现赛(感谢中国石油大学)
【题目链接】:http://acm.split.hdu.edu.cn/showproblem.php?pid=5992
【题解】
先炫耀一下;
kd-tree;
如果没学过kd-tree不建议你再往下看。
这里不能用那个四边形的估价函数;会超时。
有一个更好的估价函数是
judge=(op.d[fx]-t[rt].d[fx])^2;
op是输入的询问,d[2]表示坐标;(二维)
这里的fx是kd-tree中当前这个域的划分依据,fx==0表示是以x轴作为划分依据、fx==1表示是以y轴作为划分依据;
具体点
int zuo = t[rt].l,you = t[rt].r;
if (op.d[fx]>t[rt].d[fx])//先搞fx维坐标离操作坐标近的;
swap(zuo,you);
query(zuo,1-fx);//优先搞"左"子树
bool should = false;//判断要不要搞右子树;
if (dis == INF)//如果距离为正无穷表示还没有更新过答案就要搞
should = true;
else
{
LL ju = sqr(op.d[fx]-t[rt].d[fx]);//否则看看这个划分依据fx的维当前这个fx坐标与操作坐标的距离的平方
//经过了swap "you"子树内全部都是比t[rt].d[fx]小或全都比它大的节点;
if (ju <= dis)//如果估价函数比当前更新到的答案小;那么就要搞右子树
should = true;//如果估价函数比当前更新到的答案还要大,那么就不要搞右子树了;
}//因为如果继续搞右子树,fx这一维的坐标在右子树里面是单调的;ju只会越来越大;
if (should)
query(you,1-fx);
除此之外;还可以在每个树的节点里面储存以这个节点为根的子树下面最低消费最小的min;如果min都大于op.n则可以不用进入子树了;
(交程序的时候选g++不然会莫名TLE);
【完整代码】
#include <cstdio>
#include <algorithm>
#define LL long long
using namespace std;
const int MAXN = 205000;
const LL INF = 1e18;
struct point
{
int min, n, dot, l,r;
LL d[2];
};
int n, m, root, now;
LL dis;
point t[MAXN];
point op,ans;
void input_data()
{
scanf("%d%d", &n,&m);
for (int i = 1; i <= n; i++)
{
scanf("%I64d%I64d%d", &t[i].d[0], &t[i].d[1],&t[i].n);
t[i].dot = i;
}
}
bool cmp_1(point a, point b)
{
return a.d[now] < b.d[now];
}
void gengxin(int father, int son)
{
if (t[father].min > t[son].min)
t[father].min = t[son].min;
}
void up_data(int rt)
{
t[rt].min = t[rt].n;
int l = t[rt].l, r = t[rt].r;
if (l) gengxin(rt, l);
if (r) gengxin(rt, r);
}
int build(int begin, int end, int fa,int fx)
{
int m = (begin + end) >> 1;
now = fx;
nth_element(t + begin, t + m, t + end + 1, cmp_1);
if (begin < m)
t[m].l = build(begin, m - 1, m, 1 - fx);
else
t[m].l = 0;
if (m < end)
t[m].r = build(m + 1, end, m, 1 - fx);
else
t[m].r = 0;
up_data(m);
return m;
}
LL sqr(LL x)
{
return x*x;
}
void query(int rt,int fx)
{
if (!rt)
return;
int temp1 = t[rt].min;
if (temp1 > op.n)
return;
if (t[rt].n <= op.n)
{
LL dd = sqr(op.d[0]-t[rt].d[0])+sqr(op.d[1]-t[rt].d[1]);
if (dd < dis || (dd==dis && t[rt].dot < ans.dot))
{
dis = dd;
ans.d[0] = t[rt].d[0];
ans.d[1] = t[rt].d[1];
ans.n = t[rt].n;
ans.dot = t[rt].dot;
}
}
int zuo = t[rt].l,you = t[rt].r;
if (op.d[fx]>t[rt].d[fx])
swap(zuo,you);
query(zuo,1-fx);
bool should = false;
if (dis == INF)
should = true;
else
{
LL ju = sqr(op.d[fx]-t[rt].d[fx]);
if (ju <= dis)
should = true;
}
if (should)
query(you,1-fx);
}
void get_ans()
{
root = build(1, n, 0, 0);
for (int i = 1; i <= m; i++)
{
scanf("%I64d%I64d%d",&op.d[0],&op.d[1],&op.n);
dis = INF;
query(root,0);
printf("%I64d %I64d %d\n",ans.d[0],ans.d[1],ans.n);
}
}
int main()
{
//freopen("F:\\rush.txt","r",stdin);
int T;
scanf("%d",&T);
while (T--)
{
input_data();
get_ans();
}
return 0;
}