SJY摆棋子
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 4696 Solved: 1622
[ Submit][ Status][ Discuss]
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
HINT
kdtree可以过
Source
解题思路:kd-tree
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cctype>
#include <map>
#include <cmath>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
const int N = 2000000 + 5;
const int demension = 2;//二维
struct node
{
int pos[demension];
int ma[demension], mi[demension];
int l, r;
}a[N], x;
int cmpDem;//以第cmpDem维作比较
int root, op, n, q, ans;
bool cmp(const node &a, const node&b)
{
if (a.pos[cmpDem] != b.pos[cmpDem]) return a.pos[cmpDem] < b.pos[cmpDem];
else return a.pos[!cmpDem] < b.pos[!cmpDem];
}
void Merge(int k)
{
for (int i = 0; i < demension; i++)
{
if (a[k].l)
{
a[k].ma[i] = max(a[k].ma[i], a[a[k].l].ma[i]);
a[k].mi[i] = min(a[k].mi[i], a[a[k].l].mi[i]);
}
if (a[k].r)
{
a[k].ma[i] = max(a[k].ma[i], a[a[k].r].ma[i]);
a[k].mi[i] = min(a[k].mi[i], a[a[k].r].mi[i]);
}
}
}
void Merge(int x, int y)
{
a[x].ma[0] = max(a[x].ma[0], a[y].ma[0]);
a[x].ma[1] = max(a[x].ma[1], a[y].ma[1]);
a[x].mi[0] = min(a[x].mi[0], a[y].mi[0]);
a[x].mi[1] = min(a[x].mi[1], a[y].mi[1]);
}
int dis(int k)
{
int dis = 0;
for (int i = 0; i < demension; i++)
{
if (x.pos[i] < a[k].mi[i]) dis += (a[k].mi[i] - x.pos[i]);
if (x.pos[i] > a[k].ma[i]) dis += (x.pos[i] - a[k].ma[i]);
}
return dis;
}
int build(int l, int r, int k)
{
if (l > r) return 0;
int mid = (l + r) / 2;
//以第mid个元素为中心排序
cmpDem = k;
nth_element(a + l, a + mid, a + r + 1, cmp);
//左右子树
a[mid].l = build(l, mid - 1, k ^ 1);
a[mid].r = build(mid + 1, r, k ^ 1);
Merge(mid);
return mid;
}
int update(int k, int p)
{
if (!k) return n;
Merge(k, n);
if (a[k].pos[p] > a[n].pos[p]) a[k].l = update(a[k].l, p ^ 1);
else a[k].r = update(a[k].r, p ^ 1);
return k;
}
void query(int k, int p)
{
if (!k) return;
//更新ans
ans = min(ans, abs(x.pos[0] - a[k].pos[0]) + abs(x.pos[1] - a[k].pos[1]));
int ld = a[k].l ? dis(a[k].l) : INF, rd = a[k].r ? dis(a[k].r) : INF;
if (min(ld, rd) >= ans) return;
if (ld < rd)
{
query(a[k].l, p ^ 1);
if (rd < ans) query(a[k].r, p ^ 1);
}
else
{
query(a[k].r, p ^ 1);
if (ld < ans) query(a[k].l, p ^ 1);
}
}
int main()
{
while (~scanf("%d%d", &n, &q))
{
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &a[i].pos[0], &a[i].pos[1]);
a[i].l = a[i].r = 0;
a[i].ma[0] = a[i].mi[0] = a[i].pos[0];
a[i].ma[1] = a[i].mi[1] = a[i].pos[1];
}
root = build(1, n, 0);
while (q--)
{
scanf("%d%d%d", &op, &x.pos[0], &x.pos[1]);
ans = INF;
if (op == 2)
{
query(root, 0);
printf("%d\n", ans);
}
else
{
a[++n] = x;
a[n].l = a[n].r = 0;
a[n].ma[0] = a[n].mi[0] = a[n].pos[0];
a[n].ma[1] = a[n].mi[1] = a[n].pos[1];
update(root, 0);
}
}
}
return 0;
}