[SDOI2010]捉迷藏

嘟嘟嘟

k-d tree板儿题。
建完树后对每一个点求一遍最小和最大曼哈顿距离,是曼哈顿,不是欧几里得。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const ll INF = 1e18;
const db eps = 1e-8;
const int maxn = 1e5 + 5;
inline ll read()
{
    ll ans = 0;
    char ch = getchar(), last = ' ';
    while(!isdigit(ch)) {last = ch; ch = getchar();}
    while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
    if(last == '-') ans = -ans;
    return ans;
}
inline void write(ll x)
{
    if(x < 0) x = -x, putchar('-');
    if(x >= 10) write(x / 10);
    putchar(x % 10 + '0');
}

int n, Dim;
struct Tree
{
    int ch[2], id;
    ll d[2], Min[2], Max[2];
    In bool operator < (const Tree& oth)const
    {
        return d[Dim] < oth.d[Dim];
    }
}t[maxn], a[maxn], b[maxn];
int root, tcnt = 0;
In void pushup(int now)
{
    for(int i = 0; i < 2; ++i)
    {
        if(t[now].ch[0])
        {
            t[now].Max[i] = max(t[now].Max[i], t[t[now].ch[0]].Max[i]);
            t[now].Min[i] = min(t[now].Min[i], t[t[now].ch[0]].Min[i]);
        }
        if(t[now].ch[1])
        {
            t[now].Max[i] = max(t[now].Max[i], t[t[now].ch[1]].Max[i]);
            t[now].Min[i] = min(t[now].Min[i], t[t[now].ch[1]].Min[i]);
        }
    }
}
In void build(int& now, int L, int R, int d)
{
    if(L > R) return;
    int mid = (L + R) >> 1;
    Dim = d;
    nth_element(a + L, a + mid, a + R + 1);
    t[now = ++tcnt] = a[mid];
    t[now].ch[0] = t[now].ch[1] = 0; t[now].id = a[mid].id;
    t[now].Min[0] = t[now].Max[0] = t[now].d[0];
    t[now].Min[1] = t[now].Max[1] = t[now].d[1]; 
    build(t[now].ch[0], L, mid - 1, d ^ 1);
    build(t[now].ch[1], mid + 1, R, d ^ 1);
    pushup(now);
}
In ll dis(int now, ll* d)
{
    return abs(t[now].d[0] - d[0]) + abs(t[now].d[1] - d[1]);
}
In ll price_Max(int now, ll* d)
{
    ll ret = 0;
    for(int i = 0; i < 2; ++i)
    {
        ll Max = max(abs(t[now].Max[i] - d[i]), abs(t[now].Min[i] - d[i]));
        ret += Max;
    }
    return ret;
}
In ll price_Min(int now, ll * d)
{
    ll ret = 0;
    for(int i = 0; i < 2; ++i)
        if(t[now].Min[i] > d[i]) ret += t[now].Min[i] - d[i];
        else if(t[now].Max[i] < d[i]) ret += d[i] - t[now].Max[i];
    return ret;
}
ll Max = -1, Min = INF;
In void query_Max(int now, ll* d, int id)
{
    if(!now) return;
    if(t[now].id ^ id) Max = max(Max, dis(now, d));
    ll disL = price_Max(t[now].ch[0], d), disR = price_Max(t[now].ch[1], d);
    if(disL < disR) swap(disL, disR), swap(t[now].ch[0], t[now].ch[1]);
    if(disL > Max) query_Max(t[now].ch[0], d, id);
    if(disR > Max) query_Max(t[now].ch[1], d, id);
}
In void query_Min(int now, ll* d, int id)
{
    if(!now) return;
    if(t[now].id ^ id) Min = min(Min, dis(now, d));
    ll disL = price_Min(t[now].ch[0], d), disR = price_Min(t[now].ch[1], d);
    if(disL > disR) swap(disL, disR), swap(t[now].ch[0], t[now].ch[1]);
    if(disL < Min) query_Min(t[now].ch[0], d, id);
    if(disR < Min) query_Min(t[now].ch[1], d, id);
}

int main()
{
    n = read();
    for(int i = 1; i <= n; ++i) a[i].d[0] = read(), a[i].d[1] = read(), a[i].id = i, b[i] = a[i];
    build(root, 1, n, 0);
    ll ans = INF;
    for(int i = 1; i <= n; ++i)
    {
        Min = INF, Max = -1;
        query_Max(root, b[i].d, i); query_Min(root, b[i].d, i);
        ans = min(ans, Max - Min);
    }
    write(ans), enter;
    return 0;
}

转载于:https://www.cnblogs.com/mrclr/p/10283596.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值