题目大意:平面上有一些点,问一个点周围离它最近的点的曼哈顿距离是多少。支持动态加点。
思路:CDQ分治可以离线解决,但是SJY是卡CDQ的,天使玩偶可以过。毕竟K-D树的O(sqrt(n))的时间复杂度摆在那。
K-D树理解起来其实不难,有k个维度的时候,每一层按照一个维度排序,取出按照这个维度排序的中位数,当作这个块的根,然后将这个块分开。还有一个比较重要的东西就是估价函数,这个函数根据不同的题可能不同。股价函数的主要用途就是对搜索进行剪枝,如果估价函数就已经大于当前的最优答案了,那就不用搜这一枝了。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 500010 #define INF 0x3f3f3f3f using namespace std; #define min(a,b) ((a) < (b) ? (a):(b)) #define max(a,b) ((a) > (b) ? (a):(b)) #define abs(a) ((a) > 0 ? (a):-(a)) int dim; struct Point{ int x,y; Point(int _,int __):x(_),y(__) {} Point() {} void Read() { scanf("%d%d",&x,&y); } }point[MAX << 1]; inline bool cmp(const Point &p1,const Point &p2) { if(dim) return p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y); return p1.y < p2.y || (p1.y == p2.y && p1.x < p2.x); } inline int Calc(const Point &p1,const Point &p2) { return abs(p1.x - p2.x) + abs(p1.y - p2.y); } struct KDTree{ int x0,y0,x1,y1; KDTree *son[2]; Point root; void *operator new(size_t,const Point &p,KDTree *_,KDTree *__) { static KDTree mempool[MAX << 1],*C = mempool; C->root = p; C->x0 = C->x1 = p.x; C->y0 = C->y1 = p.y; C->son[0] = _,C->son[1] = __; return C++; } int Dis(const Point &p)const { int re = 0; if(p.x < x0) re += x0 - p.x; if(p.x > x1) re += p.x - x1; if(p.y < y0) re += y0 - p.y; if(p.y > y1) re += p.y - y1; return re; } void Maintain(KDTree *a) { x0 = min(x0,a->x0); x1 = max(x1,a->x1); y0 = min(y0,a->y0); y1 = max(y1,a->y1); } }none,*nil = &none,*root; KDTree *BuildTree(int l,int r,bool d) { if(l > r) return nil; dim = d; int mid = (l + r) >> 1; nth_element(point + l,point + mid,point + r + 1,cmp); KDTree *re = new (point[mid],BuildTree(l,mid - 1,!d),BuildTree(mid + 1,r,!d))KDTree; if(re->son[0] != nil) re->Maintain(re->son[0]); if(re->son[1] != nil) re->Maintain(re->son[1]); return re; } int ans; void Ask(KDTree *a,const Point &p) { int temp = Calc(a->root,p); ans = min(ans,temp); int l = a->son[0] == nil ? INF:a->son[0]->Dis(p); int r = a->son[1] == nil ? INF:a->son[1]->Dis(p); if(l < r) { if(a->son[0] != nil) Ask(a->son[0],p); if(r < ans && a->son[1] != nil) Ask(a->son[1],p); } else { if(a->son[1] != nil) Ask(a->son[1],p); if(l < ans && a->son[0] != nil) Ask(a->son[0],p); } } void Insert(const Point &p) { KDTree *now = root; KDTree *_new = new (p,nil,nil)KDTree; dim = 0; while(1) { now->Maintain(_new); if(cmp(p,now->root)) { if(now->son[0] == nil) { now->son[0] = _new; break; } else now = now->son[0]; } else { if(now->son[1] == nil) { now->son[1] = _new; break; } else now = now->son[1]; } dim ^= 1; } } int points,asks; int main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("wa.out","w",stdout); #endif cin >> points >> asks; for(int i = 1; i <= points; ++i) point[i].Read(); root = BuildTree(1,points,0); for(int flag,x,y,i = 1; i <= asks; ++i) { scanf("%d%d%d",&flag,&x,&y); if(flag == 1) Insert(Point(x,y)); else { ans = INF; Ask(root,Point(x,y)); printf("%d\n",ans); } } return 0; }
BZOJ 2648 SJY摆棋子 / 2716 Violet 3 天使玩偶 K-D树
原文地址:http://blog.csdn.net/jiangyuze831/article/details/42121279