BZOJ 2648 SJY摆棋子(KD树)
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2716
【题目大意】
给出一些点,同时不断插入点和询问某点离插入点最近距离
【题解】
我们对于给定的点直接建树,之后动态插入查询即可,重建会超时,
直接插入就可以过了
【代码】
#include <cstdio> #include <algorithm> using namespace std; const int N=1500000,INF=1e9; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } namespace KD_Tree{ struct Dot{ int d[2],mn[2],mx[2],l,r,sz; Dot(){l=r=0;} Dot(int x,int y){d[0]=x;d[1]=y;l=r=sz=0;} int& operator [] (int x){return d[x];} }; int D,pt[N],dcnt=0; Dot T[N],p[N]; bool operator<(Dot a,Dot b){return a[D]<b[D];} inline void umax(int&a,int b){if(a<b)a=b;} inline void umin(int&a,int b){if(a>b)a=b;} inline bool cmp(int x,int y){return T[x][D]<T[y][D];} inline void up(int x){ T[x].sz=T[T[x].l].sz+T[T[x].r].sz+1; T[x].mn[0]=T[x].mx[0]=T[x][0]; T[x].mn[1]=T[x].mx[1]=T[x][1]; if(T[x].l){ umax(T[x].mx[0],T[T[x].l].mx[0]); umin(T[x].mn[0],T[T[x].l].mn[0]); umax(T[x].mx[1],T[T[x].l].mx[1]); umin(T[x].mn[1],T[T[x].l].mn[1]); } if(T[x].r){ umax(T[x].mx[0],T[T[x].r].mx[0]); umin(T[x].mn[0],T[T[x].r].mn[0]); umax(T[x].mx[1],T[T[x].r].mx[1]); umin(T[x].mn[1],T[T[x].r].mn[1]); } } inline int NewDot(int x,int y){ ++dcnt; pt[dcnt]=dcnt; T[dcnt][0]=x; T[dcnt][1]=y; return up(dcnt),dcnt; } void AddDot(int x,int y){ ++dcnt; pt[dcnt]=dcnt; p[dcnt][0]=x; p[dcnt][1]=y; } // 曼哈顿距离估价函数 inline int dist(int p1,int px,int py){ int dis=0; if(px<T[p1].mn[0])dis+=T[p1].mn[0]-px; if(px>T[p1].mx[0])dis+=px-T[p1].mx[0]; if(py<T[p1].mn[1])dis+=T[p1].mn[1]-py; if(py>T[p1].mx[1])dis+=py-T[p1].mx[1]; return dis; } //查询(px,py)最近点距离 int ans=0; inline void ask(int x,int px,int py){ int dl,dr,d0=abs(T[x][0]-px)+abs(T[x][1]-py); if(d0<ans)ans=d0; dl=T[x].l?dist(T[x].l,px,py):INF; dr=T[x].r?dist(T[x].r,px,py):INF; if(dl<dr){ if(dl<ans)ask(T[x].l,px,py); if(dr<ans)ask(T[x].r,px,py); }else{ if(dr<ans)ask(T[x].r,px,py); if(dl<ans)ask(T[x].l,px,py); } } int query(int x,int px,int py){ ans=INF; ask(x,px,py); return ans; } void Insert(int&x,int D,const Dot&p){ if(!x){x=NewDot(p.d[0],p.d[1]);return;} if(p.d[D]<T[x][D])Insert(T[x].l,D^1,p); else Insert(T[x].r,D^1,p); up(x); } // 建树 int build(int l,int r,int now){ int mid=(l+r)>>1; D=now; nth_element(p+l,p+mid,p+r+1); T[mid]=p[mid]; for(int i=0;i<2;i++)T[mid].mn[i]=T[mid].mx[i]=T[mid][i]; if(l<mid)T[mid].l=build(l,mid-1,now^1); if(r>mid)T[mid].r=build(mid+1,r,now^1); return up(mid),mid; } // 暴力重构 int Rebuild(int l,int r,int now){ if(l>r)return 0; int mid=(l+r)>>1,x; D=now; nth_element(pt+l,pt+mid,pt+r+1,cmp); x=pt[mid]; T[x].l=Rebuild(l,mid-1,now^1); T[x].r=Rebuild(mid+1,r,now^1); return up(x),x; } } int n,m,x,y,root=0,c; int main(){ n=read(); m=read(); for(int i=1;i<=n;i++)KD_Tree::AddDot(read(),read()); root=KD_Tree::build(1,KD_Tree::dcnt,0); while(m--){ if(read()==1)KD_Tree::Insert(root,0,KD_Tree::Dot(read(),read())); else printf("%d\n",KD_Tree::query(root,read(),read())); // if(KD_Tree::dcnt%5000==0)root=KD_Tree::Rebuild(1,KD_Tree::dcnt,0); // 重构会超时,不重构能过 }return 0; }
愿你出走半生,归来仍是少年