KDtree模板
模板题:luogu4169 有个点要吸氧才能过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const double alpha=0.8; const int M=3; const int N=3000010; const int inf=0x3f3f3f3f; int WD=2,now; int cnt,ans; int Q[N],B,A; int n,m,root; int bad,badfa,badwd; struct Point{ int x[M]; }P[N]; struct Tree{ int l,r; int siz; int MIN[M],MAX[M]; Point p; }T[N]; bool operator <(Point A,Point B){ return A.x[now]<B.x[now]; } int newpoint(Point p){ int pos=0; if(B)pos=Q[B--]; else pos=++cnt; T[pos].l=T[pos].r=T[pos].siz=0; T[pos].p=p; return pos; } void update(int pos){ for(int i=0;i<WD;i++){ T[pos].MAX[i]=T[pos].MIN[i]=T[pos].p.x[i]; if(T[pos].l){ T[pos].MIN[i]=min(T[pos].MIN[i],T[T[pos].l].MIN[i]); T[pos].MAX[i]=max(T[pos].MAX[i],T[T[pos].l].MAX[i]); } if(T[pos].r){ T[pos].MIN[i]=min(T[pos].MIN[i],T[T[pos].r].MIN[i]); T[pos].MAX[i]=max(T[pos].MAX[i],T[T[pos].r].MAX[i]); } } T[pos].siz=T[T[pos].l].siz+T[T[pos].r].siz+1; return; } int build(int l,int r,int wd){ if(l>r)return 0; int mid=(l+r)/2; now=wd; nth_element(P+l,P+mid,P+r+1); int pos=newpoint(P[mid]); T[pos].l=build(l,mid-1,(wd+1)%WD); T[pos].r=build(mid+1,r,(wd+1)%WD); update(pos); return pos; } bool check(int pos){ if(1ll*T[pos].siz*alpha<1ll*T[T[pos].l].siz)return 0; if(1ll*T[pos].siz*alpha<1ll*T[T[pos].r].siz)return 0; return 1; } void pia(int pos,int num){ if(T[pos].l)pia(T[pos].l,num); P[++A]=T[pos].p; Q[++B]=pos; if(T[pos].r)pia(T[pos].r,T[T[pos].l].siz+1+num); } void rebuild(){ if(!bad)return; int next=(T[badfa].r==bad?1:0),last=bad; A=0;pia(bad,0);bad=build(1,A,badwd); if(next==0)T[badfa].l=bad; else T[badfa].r=bad; if(last==root)root=bad; } int Ins(int pos,Point p,int wd,int fa){ if(!pos){ pos=newpoint(p); update(pos); return pos; } if(p.x[wd]<T[pos].p.x[wd]){ T[pos].l=Ins(T[pos].l,p,(wd+1)%WD,pos); }else{ T[pos].r=Ins(T[pos].r,p,(wd+1)%WD,pos); } update(pos); if(!check(pos)){ bad=pos; badfa=fa; badwd=wd; } return pos; } void Insert(Point p){ bad=badfa=0; root=Ins(root,p,0,0); rebuild(); } int dist(Point A,Point B){ int res=0; for(int i=0;i<WD;i++)res+=abs(A.x[i]-B.x[i]); return res; } int getdist(Point A,int pos){ int res=0; for(int i=0;i<WD;i++){ res+=max(0,A.x[i]-T[pos].MAX[i]); res+=max(0,T[pos].MIN[i]-A.x[i]); } return res; } void query(int pos,Point p){ ans=min(ans,dist(p,T[pos].p)); int Ldist=inf,Rdist=inf; if(T[pos].l)Ldist=getdist(p,T[pos].l); if(T[pos].r)Rdist=getdist(p,T[pos].r); if(Ldist<Rdist){ if(Ldist<ans)query(T[pos].l,p); if(Rdist<ans)query(T[pos].r,p); }else{ if(Rdist<ans)query(T[pos].r,p); if(Ldist<ans)query(T[pos].l,p); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int X,Y; scanf("%d%d",&X,&Y); P[i].x[0]=X; P[i].x[1]=Y; } root=build(1,n,0); for(int i=1;i<=m;i++){ Point tmp; int opt; scanf("%d%d%d",&opt,&tmp.x[0],&tmp.x[1]); if(opt==1){ Insert(tmp); }else{ ans=inf; query(root,tmp); printf("%d\n",ans); } } }