题目传送门
题目大意: 给出 n n n 个点,有 m m m 次操作,每次为:1、添加一个点;2、求点集中离询问点最近的点到询问点的距离;3、询问点集中离询问点最远的点到询问点的距离。
K-D tree裸题。
先维护一下每棵子树对应的矩阵。
找最近点的剪枝是:先去左右子树中离离询问点比较近的矩阵。
找最远点的剪枝:类似的,先去比较远的矩阵。
代码如下:
#include
#include
#include
using namespace std;
#define maxn 500010
#define inf 999999999
#define zuo ch[0]
#define you ch[1]
#define alpha 0.75
int n,m;
const int K=2;
struct point{int d[K];}q[maxn];
int dis(point x,point y){
int re=0;
for(int i=0;i<K;i++)re+=abs(x.d[i]-y.d[i]);
return re;
}
int C;bool cmp(point x,point y){return x.d[C]<y.d[C];}
struct KD_node *root=NULL,*null=NULL;
struct KD_node{
point x,ld,ru;
KD_node *ch[2];
int size;
KD_node(point &X,int sz):x(X),ld(X),ru(X),size(sz){zuo=you=null;}
KD_node(){}
void check(){
for(int i=0;i<K;i++){
ld.d[i]=min(x.d[i],min(zuo->ld.d[i],you->ld.d[i]));
ru.d[i]=max(x.d[i],max(zuo->ru.d[i],you->ru.d[i]));
}
}
int dis_min(point &z){
int re=0;
for(int i=0;i<K;i++)
if(z.d[i]<ld.d[i])re+=ld.d[i]-z.d[i];
else if(z.d[i]>ru.d[i])re+=z.d[i]-ru.d[i];
return re;
}
int dis_max(point &z){
int re=0;
for(int i=0;i<K;i++)
re+=max(abs(z.d[i]-ld.d[i]),abs(z.d[i]-ru.d[i]));
return re;
}
};
void init(){
null=new KD_node();null->size=0;
for(int i=0;i<K;i++){
null->ld.d[i]=inf;
null->ru.d[i]=-inf;
}
}
void build_KDtr(KD_node *&now,int l,int r,int CO=0)
{
if(l>=r)return;
int mid=l+r>>1;C=CO;
nth_element(q+l,q+mid,q+r,cmp);
now=new KD_node(q[mid],r-l);
build_KDtr(now->zuo,l,mid,(CO+1)%K);
build_KDtr(now->you,mid+1,r,(CO+1)%K);
now->check();
}
void erase(KD_node *&now){
if(now==null)return;
q[++n]=now->x;
erase(now->zuo);erase(now->you);
delete now;
}
void rebuild(KD_node *&now){n=0;erase(now);build_KDtr(now,1,n+1);}
void add_node(KD_node *&now,point x,int CO=0,bool v=false)
{
if(now==null){now=new KD_node(x,1);return;}
now->size++;
C=CO;int to=cmp(x,now->x)^1;
bool tf=false;
if(now->size*alpha<=now->ch[to]->size+1)tf=true;
add_node(now->ch[to],x,(CO+1)%K,v|tf);
if(!v&&tf)rebuild(now);
now->check();
}
int ans;
void ask_min(KD_node *&now,point x)
{
if(now==null)return;
ans=min(ans,dis(now->x,x));
int to=(now->zuo->dis_min(x)<now->you->dis_min(x))^1;
ask_min(now->ch[to],x);
if(now->ch[to^1]->dis_min(x)<ans)ask_min(now->ch[to^1],x);
}
void ask_max(KD_node *&now,point x)
{
if(now==null)return;
ans=max(ans,dis(now->x,x));
int to=(now->zuo->dis_max(x)>now->you->dis_max(x))^1;
ask_max(now->ch[to],x);
if(now->ch[to^1]->dis_max(x)>ans)ask_max(now->ch[to^1],x);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=0;j<K;j++)scanf("%d",&q[i].d[j]);
init();build_KDtr(root,1,n+1);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int id;point x;
scanf("%d",&id);
for(int j=0;j<K;j++)scanf("%d",&x.d[j]);
switch(id){
case 0:add_node(root,x);break;
case 1:ans=2*inf;ask_min(root,x);printf("%d\n",ans);break;
case 2:ans=-2*inf;ask_max(root,x);printf("%d\n",ans);break;
}
}
}