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;
    }
    
  • 相关阅读:
    linux每天一小步cp命令详解
    linux每天一小步ls命令详解
    linux每天一小步cd命令详解
    linux每天一小步rm命令详解
    linux每天一小步touch命令详解
    linux每天一小步mkdir命令详解
    input、textarea等输入框输入中文时,拼音在输入框内会触发input事件的问题
    (转)周志华:“深”为什么重要,以及还有什么深的网络
    CSS画行内分隔线
    百度之星资格赛E:C++ 与Java
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626949.html
Copyright © 2011-2022 走看看