[BZOJ4533][BeiJing2014 WinterCamp] 数据
试题描述
为了写论文,Alex经常要整理大量的数据。
这一次,Alex面临一个严峻的考验:他需要实现一个数据结构来维护一个点集。
现在,二维平面上有N个点。Alex 需要实现以下三种操作:
1.
在点集里添加一个点;
2.
给出一个点,查询它到点集里所有点的曼哈顿距离的最小值;
3.
给出一个点,查询它到点集里所有点的曼哈顿距离的最大值。
两个点的曼哈顿距离定义为它们的横坐标差的绝对值与纵坐标差的绝对值的和。这么困难的问题,Alex当然不会做,只好再次请你帮忙了。
输入
第一行包含一个整数N,表示点集最初的点数。
接下来N行,每行两个整数,依次表示每个点的横坐标和纵坐标。
第N+2行包含一个整数Q,表示询问的数目。
接下来Q行,每行三个整数,依次表示询问的类型,点的横坐标和纵坐标。0类型表示添加一个点,1类型表示查询到该点的曼哈顿距离的最小值,2类型表示查询最大值。
1 ≤ N, Q ≤ 100,000,点的坐标是不超过10^9的非负整数
输出
输出若干行,依次表示每个查询操作的答案。
输入示例
3 7 5 6 2 3 1 5 1 6 1 1 5 5 2 7 1 0 3 2 1 1 0
输出示例
1 2 4 3
数据规模及约定
见“输入”
题解
这道题kd树踩标程,我借此学了学kd树。
大概是奇数层按横坐标折半划分,偶数层按照纵坐标折半划分,插入找其所在的区域,查询找当前点与左、右子树所表示的矩形,看那个更近(或远)就先考虑哪边。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
}
#define maxn 200010
#define oo 2147483647
int n, lc[maxn], rc[maxn];
int ToT, Cur, root;
struct Node {
int x[2], mx[2], mn[2];
bool operator < (const Node& t) const { return x[Cur] < t.x[Cur]; }
} nodes[maxn];
void maintain(int o) {
int l = lc[o], r = rc[o];
for(int i = 0; i < 2; i++) {
nodes[o].mx[i] = max(max(nodes[l].mx[i], nodes[r].mx[i]), nodes[o].x[i]);
nodes[o].mn[i] = min(min(nodes[l].mn[i], nodes[r].mn[i]), nodes[o].x[i]);
}
return ;
}
void build(int& o, int L, int R, int cur) {
if(L > R) return ;
int M = L + R >> 1; o = M;
Cur = cur; nth_element(nodes + L, nodes + M, nodes + R + 1);
build(lc[o], L, M - 1, cur ^ 1); build(rc[o], M + 1, R, cur ^ 1);
maintain(o);
return ;
}
Node no;
void insert(int& o, int cur) {
if(!o) nodes[o = ++ToT] = no;
else insert(no.x[cur] < nodes[o].x[cur] ? lc[o] : rc[o], cur ^ 1);
maintain(o);
return ;
}
int calcmn(int o) {
int ans = 0;
for(int i = 0; i < 2; i++) {
if(nodes[o].mn[i] > no.x[i]) ans += nodes[o].mn[i] - no.x[i];
if(nodes[o].mx[i] < no.x[i]) ans += no.x[i] - nodes[o].mx[i];
}
return ans;
}
int querymn(int& o) {
int ans = oo;
if(!o) return ans;
ans = min(ans, abs(no.x[0] - nodes[o].x[0]) + abs(no.x[1] - nodes[o].x[1]));
int dl = calcmn(lc[o]), dr = calcmn(rc[o]);
if(dl < dr) {
if(dl < ans) ans = min(ans, querymn(lc[o]));
if(dr < ans) ans = min(ans, querymn(rc[o]));
}
else {
if(dr < ans) ans = min(ans, querymn(rc[o]));
if(dl < ans) ans = min(ans, querymn(lc[o]));
}
return ans;
}
int calcmx(int o) {
return max(abs(nodes[o].mx[0] - no.x[0]), abs(nodes[o].mn[0] - no.x[0])) + max(abs(nodes[o].mx[1] - no.x[1]), abs(nodes[o].mn[1] - no.x[1]));
}
int querymx(int& o) {
int ans = -oo;
if(!o) return ans;
ans = max(ans, abs(no.x[0] - nodes[o].x[0]) + abs(no.x[1] - nodes[o].x[1]));
int dl = calcmx(lc[o]), dr = calcmx(rc[o]);
if(dl > dr) {
if(dl > ans) ans = max(ans, querymx(lc[o]));
if(dr > ans) ans = max(ans, querymx(rc[o]));
}
else {
if(dr > ans) ans = max(ans, querymx(rc[o]));
if(dl > ans) ans = max(ans, querymx(lc[o]));
}
return ans;
}
int main() {
nodes[0].mx[0] = nodes[0].mx[1] = -oo;
nodes[0].mn[0] = nodes[0].mn[1] = oo;
n = read();
for(int i = 1; i <= n; i++) {
ToT++;
nodes[ToT].x[0] = read();
nodes[ToT].x[1] = read();
}
build(root, 1, n, 0);
int q = read();
while(q--) {
int tp = read();
no.x[0] = read();
no.x[1] = read();
if(!tp) insert(root, 0);
if(tp == 1) printf("%d\n", querymn(root));
if(tp == 2) printf("%d\n", querymx(root));
}
return 0;
}