zoukankan      html  css  js  c++  java
  • 【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
    ",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;
    }
    
  • 相关阅读:
    iOS AppIcon尺寸
    MBProgressHUD的基本使用
    所有界面锁定屏幕方向,某一个界面支持屏幕旋转~
    90. 64位整数乘法【快速乘模板】
    89. a^b【快速幂模板】
    237. 程序自动分析 【map+并查集】
    旅行商问题【山财新生赛E】
    HDU 2647 Reward 【拓扑排序反向建图+队列】
    HDU1285 确定比赛问题【拓扑排序+优先队列】
    日志统计 尺取法【蓝桥杯2018 C/C++ B组】
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626949.html
Copyright © 2011-2022 走看看