BZOJ_2716_[Violet 3]天使玩偶&&BZOJ_2648_SJY摆棋子_KDTree
BZOJ_2716_[Violet 3]天使玩偶&&BZOJ_2648_SJY摆棋子_KDTree
Description
这天,SJY显得无聊。在家自己玩。在一个棋盘上,有N个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) 。现在给出N<=500000个初始棋子。和M<=500000个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。
Input
第一行两个数 N M
以后M行,每行3个数 t x y
如果t=1 那么放下一个黑色棋子
如果t=2 那么放下一个白色棋子
Output
对于每个T=2 输出一个最小距离
Sample Input
2 3
1 1
2 3
2 1 2
1 3 3
2 4 2
1 1
2 3
2 1 2
1 3 3
2 4 2
Sample Output
1
2
2
HINT
kdtree可以过
kdtree是主要处理多维空间信息的工具。
当k=2时通常用来解决矩形查询问题,已知的一些矩形查询问题复杂度可以证明。
不过由于kdtree的实质看起来像剪枝,处理其他问题时也有很优越的时间。
kdtree像是一棵BST,它对于每层找到坐标为中位数的点当做这个点维护的信息,然后递归左右。
建树时通常横着切一刀竖着切一刀,再用nth_element来保证复杂度。
每个节点维护子树信息,mx[p][0]和mn[p][0]表示横坐标的范围,纵坐标同理。
通常插入点的时候要保证平衡而重构kdtree。
对于这道题我们维护出kdtree的信息。
查询时面对ls和rs两个矩形,分别求出他们的估价dis,即查询点到两个矩形的曼哈顿最小距离。
先递归dis小的那个,然后再判断答案和dis的关系决定是否递归另一棵子树。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 1000050 #define ls ch[p][0] #define rs ch[p][1] #define _min(x,y) ((x)<(y)?(x):(y)) #define _max(x,y) ((x)>(y)?(x):(y)) int mx[N][2],mn[N][2],ch[N][2],now,root,ans,n,m,dep[N],maxdep; inline char nc() { static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } int rd() { int x=0; char s=nc(); while(s<'0'||s>'9') s=nc(); while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+s-'0',s=nc(); return x; } char pbuf[100000],*pp=pbuf; void push(const char ch) { if(pp-pbuf==100000) fwrite(pbuf,1,100000,stdout),pp=pbuf; *pp++=ch; } void write(int x) { static char sta[35]; int top=0; do{sta[++top]=x%10,x/=10;}while(x); while(top) push(sta[top--]+'0'); push('\n'); } struct Point { int p[2]; bool operator < (const Point &u) const { return p[now]==u.p[now]?p[!now]<u.p[!now]:p[now]<u.p[now]; } }a[N]; int Abs(int x) {return x>0?x:-x;} void pushup(int p,int x) { mx[p][0]=_max(mx[p][0],mx[x][0]); mx[p][1]=_max(mx[p][1],mx[x][1]); mn[p][0]=_min(mn[p][0],mn[x][0]); mn[p][1]=_min(mn[p][1],mn[x][1]); } int build(int l,int r,int type,int fa) { int mid=(l+r)>>1; dep[mid]=dep[fa]+1; maxdep=_max(maxdep,dep[mid]); now=type; nth_element(a+l,a+mid,a+r+1); mx[mid][0]=mn[mid][0]=a[mid].p[0]; mx[mid][1]=mn[mid][1]=a[mid].p[1]; if(l<mid) ch[mid][0]=build(l,mid-1,!type,mid),pushup(mid,ch[mid][0]); if(r>mid) ch[mid][1]=build(mid+1,r,!type,mid),pushup(mid,ch[mid][1]); return mid; } void insert(int x) { int p=root; now=0; while(1) { pushup(p,x); if(a[x].p[now]<a[p].p[now]) { if(ls) p=ls; else {ls=x; pushup(p,x); dep[x]=dep[p]+1; break;} }else { if(rs) p=rs; else {rs=x; pushup(p,x); dep[x]=dep[p]+1; break;} } now=now^1; } maxdep=_max(maxdep,dep[x]); if(maxdep>100) maxdep=0,root=build(1,n,0,0); } int getdis(int x,int y,int p) { int re=0; if(x<mn[p][0]) re+=mn[p][0]-x; if(x>mx[p][0]) re+=x-mx[p][0]; if(y<mn[p][1]) re+=mn[p][1]-y; if(y>mx[p][1]) re+=y-mx[p][1]; return re; } void query(int x,int y,int p) { int re=Abs(x-a[p].p[0])+Abs(y-a[p].p[1]),dl,dr; if(re<ans) ans=re; dl=ls?getdis(x,y,ls):0x3f3f3f3f; dr=rs?getdis(x,y,rs):0x3f3f3f3f; if(dl<dr) { if(dl<ans) query(x,y,ls); if(dr<ans) query(x,y,rs); }else { if(dr<ans) query(x,y,rs); if(dl<ans) query(x,y,ls); } } int main() { n=rd(); m=rd(); int i,opt,x,y; for(i=1;i<=n;i++) a[i].p[0]=rd(),a[i].p[1]=rd(); root=build(1,n,0,0); while(m--) { opt=rd(); x=rd(); y=rd(); if(opt==1) n++,a[n].p[0]=mx[n][0]=mn[n][0]=x,a[n].p[1]=mx[n][1]=mn[n][1]=y,insert(n); else ans=0x3f3f3f3f,query(x,y,root),write(ans); } fwrite(pbuf,1,pp-pbuf,stdout); }