一、AcWing 254. 天使玩偶 洛谷:P4169
曼哈顿距离最近点:

Ayu在七年前曾经收到过一个天使玩偶,当时她把它当做时间囊埋在了地下。

而七年后的今天,Ayu却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。

我们把Ayu生活的小镇看做一个二维平面直角坐标系,而Ayu会不定时的记起可能在某个点(x,y)埋下了天使玩偶。

或者Ayu会询问你,假如她在(x,y),那么她离最近的天使玩偶可能埋下的地方有多远。

因为Ayu只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为曼哈顿距离:

dist(A,B)=|Ax−Bx|+|Ay−By|
其中Ax表示点A的横坐标,其余类似。

输入格式
第一行包含两个整数n和m,在刚开始时,Ayu已经知道有n个点可能埋着天使玩偶,接下来Ayu要进行m次操作。

接下来n行,每行两个非负整数xi,yi,表示初始n个点的坐标。

再接下来m行,每行三个非负整数 t,x,y 。

如果t=1,表示Ayu又回忆起了一个可能埋着玩偶的点(x,y)。

如果t=2,表示Ayu询问如果她在坐标(x,y),那么在已经回忆出的点里,离她最近的那个点有多远。

输出格式
对于每个t=2的询问,在单独的一行内输出该询问的结果。

数据范围
n,m≤5∗105,坐标范围为 0~1e6。

输入样例:
2 3
1 1
2 3
2 1 2
1 3 3
2 4 2
输出样例:
1
2

好吧,洛谷上吸着氧过了,AcWing TLE
据说这玩意随机数据下能达到nlogn。
可是感觉能到 nsqrt(n)的复杂度。
也可能是我选择轴点的姿势不大对。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=1000100;
const double alpha=0.75;
const int inf=0x3f3f3f3f;
struct Point
{
    int x[2];
}po[maxn];
struct node
{
    int p[2];
    int lc,rc;
    int mi[2],ma[2];
    int si;
}t[maxn];

int n,m,root,cnt,sum;
int res[2],ans;
int hui[maxn],top;
int nowd;
int dd,*pp;

bool cmp(const Point &a,const Point &b)
{
    return a.x[nowd]<b.x[nowd];
}

bool balance(int q)
{
    return (double)t[t[q].lc].si<=t[q].si*alpha&&(double)t[t[q].rc].si<=t[q].si*alpha;
}

int newnode(int k)
{
    int p=0;
    if(top) p=hui[top--];
    else p=++cnt;
    t[p].si=t[p].lc=t[p].rc=0;
    t[p].mi[0]=t[p].ma[0]=t[p].p[0]=po[k].x[0];
    t[p].mi[1]=t[p].ma[1]=t[p].p[1]=po[k].x[1];
    return p;
}

void  pushup(int p)
{
    int lc=t[p].lc,rc=t[p].rc;
    for(int i=0;i<2;i++)
    {
        if(lc) t[p].mi[i]=min(t[p].mi[i],t[lc].mi[i]),t[p].ma[i]=max(t[p].ma[i],t[lc].ma[i]);
        if(rc) t[p].mi[i]=min(t[p].mi[i],t[rc].mi[i]),t[p].ma[i]=max(t[p].ma[i],t[rc].ma[i]);
    }
    t[p].si=t[lc].si+t[rc].si+1;
}

int build(int l,int r,int d)
{
    if(l>r) return 0;
    int mid=(l+r)>>1;
    nowd=d;
    nth_element(po+l,po+mid,po+r+1,cmp);
    int p=newnode(mid);
    t[p].lc=build(l,mid-1,d^1);
    t[p].rc=build(mid+1,r,d^1);
    pushup(p);
    return p;
}

void _insert(int &p,int k,int d)
{
    if(!p)
    {
        pp=NULL;
        p=newnode(k);
        return ;
    }
    if(po[k].x[d]<t[p].p[d])
        _insert(t[p].lc,k,d^1);
    else _insert(t[p].rc,k,d^1);
    pushup(p);
    if(!balance(p)) pp=&p,dd=d;
}


void dfs(int p)
{
    if(t[p].lc) dfs(t[p].lc);
    ++sum;
    po[sum].x[0]=t[p].p[0],po[sum].x[1]=t[p].p[1];
    hui[++top]=p;
    if(t[p].rc) dfs(t[p].rc);
}

void rebuild(void)
{
    sum=0;
    dfs(*pp);
    (*pp)=build(1,sum,dd);
}

void _insert(int k)
{
    _insert(root,k,0);
    if(pp!=NULL) rebuild();
}

inline int dis(int p)
{
    return abs(t[p].p[0]-res[0])+abs(t[p].p[1]-res[1]);
}

inline int di(int p)
{
    int ans=0;
    for(int i=0;i<2;i++)
        ans+=max(t[p].mi[i]-res[i],0)+max(res[i]-t[p].ma[i],0);
    return ans;
}

void ask(int p)
{
    if(!p) return ;
    if(dis(p)<dis(ans)) ans=p;
    int dl=inf,dr=inf;
    if(t[p].lc) dl=di(t[p].lc);
    if(t[p].rc) dr=di(t[p].rc);
    if(dl<dr)
    {
        if(dl<dis(ans))
            ask(t[p].lc);
        if(dr<dis(ans))
            ask(t[p].rc);
    }
    else
    {
        if(dr<dis(ans))
            ask(t[p].rc);
        if(dl<dis(ans))
            ask(t[p].lc);
    }
}

int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&po[i].x[0],&po[i].x[1]);
    root=build(1,n,0);
    int op;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&op,&res[0],&res[1]);
        if(op==1)
        {
            n++;
            po[n].x[0]=res[0],po[n].x[1]=res[1];
            _insert(n);
        }
        else
        {
            ans=1;
            ask(root);
            printf("%d\n",dis(ans));
        }
    }
    return 0;
}

别的应用以后再补上吧。