BZOJ-2648: SJY摆棋子

[文章目录]

Description

这天,SJY显得无聊。在家自己玩。在一个棋盘上,有N个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) 。现在给出N<=500000个初始棋子。和M<=500000个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。

KD-tree模板题。
根据GXZlegend的授课:对于KD-tree维护二维平面上和定点的最近距离,只有切比雪夫距离没有被GXZlegend卡掉(曼哈顿以及欧几里得距离都被卡成n^2)
我们将曼哈顿距离转成切比雪夫距离:(x,y)->(x+y,x-y)之后拿KD-tree维护就好啦。时间复杂度O(n√n)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
inline char nc()
{
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
    x=0; char ch=nc();
    while(!isdigit(ch)) ch=nc();
    while(isdigit(ch)) x=x*10+ch-'0',ch=nc();
}
inline int Abs(int x){return x>0?x:-x;}
int rot,d,ans;
struct KD_tree
{
    int c[2],mx[2],mi[2],p[2];
}t[1001000];
bool operator < (KD_tree x,KD_tree y)
{
    return x.p[d]==y.p[d] ? x.p[d^1]<y.p[d^1] : x.p[d]<y.p[d];
}
void pushup(int p,int s)
{
    t[p].mx[0]=max(t[p].mx[0],t[s].mx[0]);
    t[p].mx[1]=max(t[p].mx[1],t[s].mx[1]);
    t[p].mi[0]=min(t[p].mi[0],t[s].mi[0]);
    t[p].mi[1]=min(t[p].mi[1],t[s].mi[1]);
}
int build(int l,int r,int now)
{
    int mid=(l+r)>>1;
    d=now; nth_element(t+l,t+mid,t+r+1);
    t[mid].mx[0]=t[mid].mi[0]=t[mid].p[0];
    t[mid].mx[1]=t[mid].mi[1]=t[mid].p[1];
    if(l<mid) t[mid].c[0]=build(l,mid-1,now^1),pushup(mid,t[mid].c[0]);
    if(r>mid) t[mid].c[1]=build(mid+1,r,now^1),pushup(mid,t[mid].c[1]);
    return mid;
}
void ins(int k)
{
    int *p=&rot;
    d=0;
    while(*p) pushup(*p,k),p=&t[*p].c[ t[k].p[d] > t[*p].p[d] ],d^=1;
    *p=k;
}
inline int getdis(int k,int x,int y)
{
    int re=0;
    if(x<t[k].mi[0]) re=max(re,t[k].mi[0]-x);
    else if(x>t[k].mx[0]) re=max(re,x-t[k].mx[0]);
    if(y<t[k].mi[1]) re=max(re,t[k].mi[1]-y);
    else if(y>t[k].mx[1]) re=max(re,y-t[k].mx[1]);
    return re;
}
void query(int k,int x,int y)
{
    int dn=max( Abs(t[k].p[0]-x),Abs(t[k].p[1]-y) ),dl,dr;
    if(dn<ans) ans=dn;
    dl=t[k].c[0] ? getdis(t[k].c[0],x,y) : inf;
    dr=t[k].c[1] ? getdis(t[k].c[1],x,y) : inf;
    if(dl<dr)
    {
        if(dl<ans) query(t[k].c[0],x,y);
        if(dr<ans) query(t[k].c[1],x,y);
    }
    else
    {
        if(dr<ans) query(t[k].c[1],x,y);
        if(dl<ans) query(t[k].c[0],x,y);
    }
}
int main()
{
    int n,m,i,sw,x,y;
    read(n); read(m);
    for(i=1;i<=n;++i)
    {
        read(x); read(y);
        t[i].p[0]=x+y;
        t[i].p[1]=x-y;
    }
    rot=build(1,n,0);
    while(m--)
    {
        read(sw); read(x); read(y);
        x=x+y; y=x-(y<<1);
        switch(sw)
        {
            case 1:
            {
                ++n;
                t[n].p[0]=t[n].mx[0]=t[n].mi[0]=x;
                t[n].p[1]=t[n].mx[1]=t[n].mi[1]=y;
                ins(n);
                break;
            }
            default:
            {
                ans=inf;
                query(rot,x,y);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注