【BZOJ1941】Hide and Seek(SDOI2010)-KD树
测试地址:Hide and Seek
做法:本题需要用到KD树。
KD树是一种维护空间中点集的数据结构,构造方法网上应该有挺多讲解,这里就不赘述了,而这道题中求曼哈顿距离最大和最小是KD树的经典应用,一次查询的复杂度最好是,最坏是,这样就可以通过此题了。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
const int inf=1000000000;
int n,rt,ansmax,ansmin,qryx,qryy,D;
struct point
{
int d[2];
}p[100010];
struct node
{
int d[2],ch[2],x[2],y[2];
}a[100010];
bool operator < (point a,point b)
{
return a.d[D]==b.d[D]?a.d[D^1]<b.d[D^1]:a.d[D]<b.d[D];
}
void pushup(int no)
{
int lc=a[no].ch[0],rc=a[no].ch[1];
if (lc)
{
a[no].x[0]=min(a[no].x[0],a[lc].x[0]);
a[no].x[1]=max(a[no].x[1],a[lc].x[1]);
a[no].y[0]=min(a[no].y[0],a[lc].y[0]);
a[no].y[1]=max(a[no].y[1],a[lc].y[1]);
}
if (rc)
{
a[no].x[0]=min(a[no].x[0],a[rc].x[0]);
a[no].x[1]=max(a[no].x[1],a[rc].x[1]);
a[no].y[0]=min(a[no].y[0],a[rc].y[0]);
a[no].y[1]=max(a[no].y[1],a[rc].y[1]);
}
}
int buildtree(int l,int r,int f)
{
if (l>r) return 0;
int mid=(l+r)>>1;
D=f;
nth_element(p+l,p+mid,p+r+1);
a[mid].d[0]=a[mid].x[0]=a[mid].x[1]=p[mid].d[0];
a[mid].d[1]=a[mid].y[0]=a[mid].y[1]=p[mid].d[1];
a[mid].ch[0]=buildtree(l,mid-1,f^1);
a[mid].ch[1]=buildtree(mid+1,r,f^1);
pushup(mid);
return mid;
}
int getmax(int no)
{
return max(qryx-a[no].x[0],a[no].x[1]-qryx)+max(qryy-a[no].y[0],a[no].y[1]-qryy);
}
int getmin(int no)
{
return max(a[no].x[0]-qryx,0)+max(qryx-a[no].x[1],0)+max(a[no].y[0]-qryy,0)+max(qryy-a[no].y[1],0);
}
void querymax(int v)
{
if (a[v].d[0]!=qryx||a[v].d[1]!=qryy)
ansmax=max(ansmax,abs(qryx-a[v].d[0])+abs(qryy-a[v].d[1]));
int dis[2]={-inf,-inf};
if (a[v].ch[0]) dis[0]=max(dis[0],getmax(a[v].ch[0]));
if (a[v].ch[1]) dis[1]=max(dis[1],getmax(a[v].ch[1]));
bool t=(dis[0]<=dis[1]);
if (dis[t]>ansmax) querymax(a[v].ch[t]);
t^=1;
if (dis[t]>ansmax) querymax(a[v].ch[t]);
}
void querymin(int v)
{
if (a[v].d[0]!=qryx||a[v].d[1]!=qryy)
ansmin=min(ansmin,abs(qryx-a[v].d[0])+abs(qryy-a[v].d[1]));
int dis[2]={inf,inf};
if (a[v].ch[0]) dis[0]=min(dis[0],getmin(a[v].ch[0]));
if (a[v].ch[1]) dis[1]=min(dis[1],getmin(a[v].ch[1]));
bool t=(dis[0]>=dis[1]);
if (dis[t]<ansmin) querymin(a[v].ch[t]);
t^=1;
if (dis[t]<ansmin) querymin(a[v].ch[t]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].d[0],&p[i].d[1]);
rt=buildtree(1,n,0);
int ans=inf;
for(int i=1;i<=n;i++)
{
qryx=p[i].d[0],qryy=p[i].d[1];
ansmax=-inf;
querymax(rt);
ansmin=inf;
querymin(rt);
ans=min(ans,ansmax-ansmin);
}
printf("%d",ans);
return 0;
}