zoukankan      html  css  js  c++  java
  • hdu 5992 kd-tree离线(在线写法常数太大了)

    题目大意:

    给你二维平面上一些旅馆,每个都有一个价格p,然后询问距离一个点,价格不高于p的旅店最近的是哪一个?

    首先如果考虑可修改的话,大家很明显可以想到可以kd-tree解决对吧,就是按价格排序,然后逐步插入。但是这么做常数太大了,不说要排序好几次,还要承担树重构的一个常数,这题还是卡的很好的,至少我被卡了常数,就很迷茫,感觉写法上自己还是有改进的地方,被卡常数了,也要知道这个算法的常数到底大不大才行,

    然后这道题其实就是把在线的东西,做成离线的就行了,先把所有点插入,然后我们怎么筛选价格呢,我们就在距离函数里加一条比较价格的就可以。虽然这种不是三维的,但是如果构造一种卡这种算法的数据也是很难的。虽然复杂度可能会有跑一些没用的点,但是实际还是很快的,没那么容易跑到上界。

    而且这题还让我学到一个东西,算欧式距离的时候,可以先不开根号,先留着,要不然sqrt的常数也不小。

    #pragma GCC optimize(2)
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #define alpha (0.75)
    using namespace std;
    typedef pair<int, pair<int, int>> P;
    typedef long long ll;
    const int N = 2e5 + 5;
    const ll INF = 1e16;
    bool dimension;
    bool reg_dimension;
    int n, m,ans_num;
    ll ans;
    struct Point
    {
        ll x, y;
        int p,num;
        Point(int X = 0, int Y = 0,int P=0) :x(X), y(Y),p(P) {}
    };
    Point a[N];
    struct Node *null;
    struct Node
    {
        int cover;
        Point p, r1, r2;
        Node *son[2];
        inline void maintain()
        {
            r1.x = min(r1.x, min(son[0]->r1.x, son[1]->r1.x));
            r1.y = min(r1.y, min(son[0]->r1.y, son[1]->r1.y));
            r1.p = min(r1.p, min(son[0]->r1.p, son[1]->r1.p));
            r2.x = max(r2.x, max(son[0]->r2.x, son[1]->r2.x));
            r2.y = max(r2.y, max(son[0]->r2.y, son[1]->r2.y));
            r2.p = max(r2.p, max(son[0]->r2.p, son[1]->r2.p));
            cover = son[0]->cover + son[1]->cover + 1;
        }
        inline bool is_bad()
        {
            return max(son[0]->cover, son[1]->cover) > cover*alpha + 5;
        }
        inline ll dis(Point p)
        {
            if (this == null)return INF;
            ll res = 0;
            //曼哈顿距离
            ll x=0,y=0;
            if (p.x<r1.x || p.x>r2.x)x += p.x < r1.x ? r1.x - p.x : p.x - r2.x;
            if (p.y<r1.y || p.y>r2.y)y += p.y < r1.y ? r1.y - p.y : p.y - r2.y;
            res=x*x+y*y;
            return res;
        }
    };
    Node mempool[N];
    Node *tail;
    Node *root;
    inline bool cmp(Point p1, Point p2)
    {
        if (dimension == 0)return p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y);
        return p1.y < p2.y || (p1.y == p2.y && p1.x < p2.x);
    }
    inline ll Pingfang_sum(Point a,Point b)
    {
        if(a.p<b.p)
            return INF;
        return 1ll*(a.x - b.x)*(a.x - b.x) + 1ll*(a.y - b.y)*(a.y - b.y);
    }
    inline void init()
    {
        tail = mempool;
        null = tail++;
        null->son[0] = null->son[1] = null;
        null->r1 = Point(INF, INF ,INF);
        null->r2 = Point(-INF, -INF,-INF);
        null->cover = 0;
        root = null;
    }
    inline Node* new_node(Point key)
    {
        Node *o;
        o = tail++;
        o->son[0] = o->son[1] = null;
        o->cover= 1;
        o->p = o->r1 = o->r2 = key;
        return o;
    }
    
    inline void travel(Node* p, vector<Node*>&x)
    {
        if (p == null)return;
        travel(p->son[0], x);
        x.push_back(p);
        travel(p->son[1], x);
    }
    inline Node* divide(vector<Node*>&x, int l, int r, bool d)
    {
        if (l >= r)return null;
        int mid = (l + r) >> 1;
        dimension = d;
        Node *o = x[mid];
        o->son[0] = divide(x, l, mid, d ^ 1);
        o->son[1] = divide(x, mid + 1, r, d ^ 1);
        o->maintain();
        return o;
    }
    inline void rebuild(Node *&o, bool d)
    {
        static vector<Node*>v;
        v.clear();
        travel(o, v);
        o = divide(v, 0, v.size(), d);
    }
    inline Node* build(int l, int r, bool d)
    {
        if (l >= r)return null;
        int mid = (l + r) >> 1;
        dimension = d;
        nth_element(a + l, a + mid, a + r, cmp);
        Node *o = new_node(a[mid]);
        o->son[0] = build(l, mid, d ^ 1);
        o->son[1] = build(mid + 1, r, d ^ 1);
        o->maintain();
        return o;
    }
    inline void query(Node *o, Point key)
    {
        if (o == null)return;
        
        ll ans_t=Pingfang_sum(key, o->p);
        
        if(ans>=ans_t)
        {
            if(ans==ans_t)
                ans_num=min(o->p.p,ans_num);
            else{
                ans_num=o->p.num;
                ans=ans_t;
            }
        }
        int dir = o->son[0]->dis(key) > o->son[1]->dis(key);
        query(o->son[dir], key);
        if (o->son[dir ^ 1]->dis(key) <= ans)
            query(o->son[dir ^ 1], key);
    }
    inline int read()
    {
        char ch = getchar();   int f = 1, x = 0;
        while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
        while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    
    Point ans_all[N],q[N],kaishi[N];
    int main()
    {
        int T;
        T=read();
        while(T--){
            init();
            int n=read(),m=read();
            for(int i=0;i<n;i++){
                a[i].x=read();a[i].y=read();a[i].p=read();
                a[i].num=i;
                kaishi[i]=a[i];
            }
            root=build(0, n, 0);
            for(int i=0;i<m;i++){
                q[i].x=read();q[i].y=read();;q[i].p=read();
                ans=INF;
                query(root, q[i]);
                printf("%d %d %d
    ",kaishi[ans_num].x,kaishi[ans_num].y,kaishi[ans_num].p);
            }
            
        }
        
        
        
    }
  • 相关阅读:
    Redis安装与基本配置(转)
    redis和redis php扩展安装(转)
    fscanf()函数具体解释
    Android Studio非gradleproject编译后的apk文件在哪?
    Android利用CountDownTimer类实现倒计时功能
    Linux系统的安装
    由一个LED闪烁问题发现的MTK的LED driver中存在的问题
    OA系统权限管理设计(转载)
    Android开发之Mediaplayer
    “两地分居”的大学师生
  • 原文地址:https://www.cnblogs.com/King-of-Dark/p/12830592.html
Copyright © 2011-2022 走看看