【bzoj2648】SJY摆棋子 KD-tree
题目描述
这天,SJY显得无聊。在家自己玩。在一个棋盘上,有N个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) 。现在给出N<=500000个初始棋子。和M<=500000个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。
输入
第一行两个数 N M
以后M行,每行3个数 t x y
如果t=1 那么放下一个黑色棋子
如果t=2 那么放下一个白色棋子
输出
对于每个T=2 输出一个最小距离
样例输入
2 3
1 1
2 3
2 1 2
1 3 3
2 4 2
样例输出
1
2
题解
KD-tree模板题
然后为了压行把insert写得比较难看
其实KD-tree这个东西和平衡树挺像的,差不多就是维护一个中序遍历,即左子树、根、右子树的某一关键字是递增的。
只不过这个关键字是不断变化的,即每一位轮流作为关键字排序(好像很高端的样子)。
所以这里使用algorithm中的STL函数:nth_element,它取出区间中指定排名的数放到指定位置,然后将小于或大于该数的放到指定位置的两端(注意一下开闭区间啥的)。
然后插入就像平衡树的插入,先找子树,直至找到空节点。
查询时采用一种启发式的思想,使用估价函数getdis,使得随机数据的时间大大减少。
然后这题好像不需要维护树不退化什么的,要维护的话直接重构即可。
#include <cstdio> #include <algorithm> #define N 1000010 #define inf 0x7fffffff using namespace std; struct data { int p[2] , maxn[2] , minn[2] , c[2]; }a[N]; int root , d , ans; bool cmp(data a , data b) { return a.p[d] == b.p[d] ? a.p[d ^ 1] < b.p[d ^ 1] : a.p[d] < b.p[d]; } void pushup(int k , int s) { a[k].maxn[0] = max(a[k].maxn[0] , a[s].maxn[0]); a[k].maxn[1] = max(a[k].maxn[1] , a[s].maxn[1]); a[k].minn[0] = min(a[k].minn[0] , a[s].minn[0]); a[k].minn[1] = min(a[k].minn[1] , a[s].minn[1]); } int build(int l , int r , int now) { int mid = (l + r) >> 1; d = now , nth_element(a + l , a + mid , a + r + 1 , cmp); a[mid].maxn[0] = a[mid].minn[0] = a[mid].p[0]; a[mid].maxn[1] = a[mid].minn[1] = a[mid].p[1]; if(l < mid) a[mid].c[0] = build(l , mid - 1 , now ^ 1) , pushup(mid , a[mid].c[0]); if(r > mid) a[mid].c[1] = build(mid + 1 , r , now ^ 1) , pushup(mid , a[mid].c[1]); return mid; } void ins(int k) { int *t = &root; d = 0; while(*t) pushup(*t , k) , t = &a[*t].c[a[k].p[d] > a[*t].p[d]] , d ^= 1; *t = k; } int getdis(int k , int x , int y) { int ans = 0; if(x < a[k].minn[0]) ans += a[k].minn[0] - x; if(x > a[k].maxn[0]) ans += x - a[k].maxn[0]; if(y < a[k].minn[1]) ans += a[k].minn[1] - y; if(y > a[k].maxn[1]) ans += y - a[k].maxn[1]; return ans; } void query(int k , int x , int y) { int dn = abs(x - a[k].p[0]) + abs(y - a[k].p[1]) , dl , dr; if(dn < ans) ans = dn; dl = a[k].c[0] ? getdis(a[k].c[0] , x , y) : inf; dr = a[k].c[1] ? getdis(a[k].c[1] , x , y) : inf; if(dl < dr) { if(dl < ans) query(a[k].c[0] , x , y); if(dr < ans) query(a[k].c[1] , x , y); } else { if(dr < ans) query(a[k].c[1] , x , y); if(dl < ans) query(a[k].c[0] , x , y); } } int main() { int n , m , i , opt , x , y; scanf("%d%d" , &n , &m); for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &a[i].p[0] , &a[i].p[1]); root = build(1 , n , 0); while(m -- ) { scanf("%d%d%d" , &opt , &x , &y); if(opt == 1) n ++ , a[n].p[0] = a[n].maxn[0] = a[n].minn[0] = x , a[n].p[1] = a[n].maxn[1] = a[n].minn[1] = y , ins(n); else ans = inf , query(root , x , y) , printf("%d\n" , ans); } return 0; }