【裸K-D树】BZOJ 2648

来源:互联网 发布:哪的java技术培训好 编辑:程序博客网 时间:2024/05/19 04:54

Problem Description

棋盘上原本有,n个黑棋。
有两种操作:
1 x y 插入一个黑色棋子
2 x y 输出距离这个白色棋子最近的黑色棋子距离(这里的距离是曼哈顿距离

思路:

参考ldq大佬博客
K-D树,其实就是一个k维的搜索树。这道题k = 2而已。

#include<bits/stdc++.h>using namespace std;const int DIM = 2;//维度,题目是二维const int inf = 0x3f3f3f3f;const int MAX = 500005;struct node{    int l, r;    int cd[DIM], maxn[DIM], minn[DIM];//分别代表坐标,以这个结点的为根的子树每一维最大值,和每一维最小值    inline void maintain()//初始化    {        l = r = 0;        for(int i = 0; i < DIM; i++)            maxn[i] = minn[i] = cd[i];    }}tree[2*MAX];int D;//第几维bool operator < (const node &a, const node &b)//重载从小到大{    return a.cd[D] < b.cd[D];}inline void Merge(int mid)//归并,也就是向上更新{    //主要就是为了更新该结点maxn[], minn[]    int son[2] = {tree[mid].l, tree[mid].r};    for(int i = 0; i < 2; i++)    {        if(!son[i]) continue;        for(int j = 0; j < DIM; j++)        {            tree[mid].maxn[j] = max(tree[mid].maxn[j], tree[son[i]].maxn[j]);            tree[mid].minn[j] = min(tree[mid].minn[j], tree[son[i]].minn[j]);        }    }}int build(int l, int r, int now)//建树{    int mid = (l+r)>>1;    D = now;    nth_element(tree+l, tree+mid, tree+r+1);//D维时,以mid这点为中点,左小 右大    tree[mid].maintain();//初始化    if(l < mid) tree[mid].l = build(l, mid-1, (now+1)%DIM);    if(r > mid) tree[mid].r = build(mid+1, r, (now+1)%DIM);    Merge(mid);//归并,向上更新    return mid;}int partionMin(int o, int k)//求k这个点,到o这个子树所有点,可能的最小距离值{    int red = 0;    for(int i = 0; i < DIM; i++)    {        if(tree[k].cd[i] > tree[o].maxn[i]) red += tree[k].cd[i] - tree[o].maxn[i];        if(tree[k].cd[i] < tree[o].minn[i]) red += tree[o].minn[i] - tree[k].cd[i];    }    return red;}int ans;void Query(int o, int k)//查找距离k这个点最近的距离{    int dm = abs(tree[o].cd[0] - tree[k].cd[0]) + abs(tree[o].cd[1] - tree[k].cd[1]);//曼哈顿距离    if(ans > dm) ans = dm;//更新    int dl = tree[o].l ? partionMin(tree[o].l, k) : inf;//如果左子树存在就求k这个点,到tree[o].l这个子树所有点,可能的最小距离值。否则无穷    int dr = tree[o].r ? partionMin(tree[o].r, k) : inf;//    if(dl < dr)//目的优化时间复杂度    {        if(dl < ans) Query(tree[o].l, k);        if(dr < ans) Query(tree[o].r, k);    }    else    {        if(dr < ans) Query(tree[o].r, k);        if(dl < ans) Query(tree[o].l, k);    }}void Insert(int &o, int k, int now)//插入操作{    if(o == 0)//代表到叶子结点的儿子    {        o = k;//更新就好了        return ;    }    if(tree[k].cd[now] < tree[o].cd[now]) Insert(tree[o].l, k, (now+1)%DIM);    else Insert(tree[o].r, k, (now+1)%DIM);    Merge(o);}int main(){    int n, m, i, j;    while(~scanf("%d %d", &n, &m))    {        for(i = 1; i <= n; i++)            for(j = 0; j < DIM; j++)            scanf("%d", &tree[i].cd[j]);        int pos = n + 1;        int root = build(1, n, 0);        int op;        while(m--)        {            scanf("%d", &op);            for(j = 0; j < DIM; j++) scanf("%d", &tree[pos].cd[j]);            if(op == 1)            {                tree[pos].maintain();                Insert(root, pos, 0);                pos++;            }            else            {                ans = inf;                Query(root, pos);                printf("%d\n", ans);            }        }    }}
原创粉丝点击