题目链接
首先,对于T==2的时候,查询是个很好解决的问题,关键就是在于插入怎么处理了。
我们像做一个可持久化数据结构一样,我们对KD-Tree也进行可持久化,然后问题就变成了每次插入一个点,但是这样以来就是会使得查询的时候,我们的估值函数应该如何处理呢?
估值函数的处理,就是对于每个区间段,处理出来它的区间的最值范围,最小值和最大值,然后呢,对于最近可能的曼哈顿距离,如此求解:
int fx(int rt)
{
if(!rt) return INF;
int sum = 0;
for(int i=0; i<K; i++) sum += max(0, mn[rt][i] - q.d[i]) + max(0, q.d[i] - mx[rt][i]);
return sum;
}
将原来的点集看成了区间,只有在这个区间外面才有值。
这道题的问题并不在于此,还有就是常数问题。
如果把这题的空间像正常线段树一样开4倍是不可以的,也是会TLE的,内存占用过大了吧。所以,有多少个点就开多少个。这是一个优化。
还有,这道题的读入很大,不妨使用快速读入来加速优化。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
inline int read()
{
int x=0; char c = getchar();
while (c<'0' || c>'9') c = getchar();
while (c>='0'&&c<='9') { x = x*10+c-'0';c = getchar(); }
return x;
}
const int maxK = 2, maxN = 1e6 + 7, K = 2;
int N, M, op;
struct node
{
int d[maxK]; int id;
node(int a=0, int b=0, int c=0):d{a, b}, id(c) {}
friend bool operator < (node e1, node e2) { return e1.d[op] < e2.d[op]; }
void In() { for(int i=0; i<K; i++) d[i] = read(); }
} a[maxN], b[maxN];
inline bool cmp(node e1, node e2) { return e1.d[op] < e2.d[op]; }
node q, point;
int dis(node a, node b)
{
int sum = 0;
for(int i=0; i<K; i++) sum += abs(a.d[i] - b.d[i]);
return sum;
}
node tree[maxN];
int lc[maxN], rc[maxN], tot, root;
int mx[maxN][maxK], mn[maxN][maxK];
int key[maxN];
double var[maxN];
int ans;
int fx(int rt)
{
if(!rt) return INF;
int sum = 0;
for(int i=0; i<K; i++) sum += max(0, mn[rt][i] - q.d[i]) + max(0, q.d[i] - mx[rt][i]);
return sum;
}
inline void pushup(int rt)
{
for(int i=0; i<K; i++)
{
if(lc[rt] && rc[rt])
{
mn[rt][i] = min(tree[rt].d[i], min(mn[lc[rt]][i], mn[rc[rt]][i]));
mx[rt][i] = max(tree[rt].d[i], max(mx[lc[rt]][i], mx[rc[rt]][i]));
}
else if(lc[rt])
{
mn[rt][i] = min(tree[rt].d[i], mn[lc[rt]][i]);
mx[rt][i] = max(tree[rt].d[i], mx[lc[rt]][i]);
}
else if(rc[rt])
{
mn[rt][i] = min(tree[rt].d[i], mn[rc[rt]][i]);
mx[rt][i] = max(tree[rt].d[i], mx[rc[rt]][i]);
}
else mn[rt][i] = mx[rt][i] = tree[rt].d[i];
}
}
void build(int &rt, int l, int r, int P)
{
if(l > r) return;
int mid = HalF; rt = mid;
key[rt] = P; op = P;
nth_element(a + l, a + mid, a + r + 1, cmp);
tree[rt] = a[mid];
build(lc[rt], l, mid - 1, P ^ 1); build(rc[rt], mid + 1, r, P ^ 1);
pushup(rt);
}
void Insert(int &rt, int P)
{
if(!rt)
{
rt = ++tot;
tree[rt] = q;
key[rt] = P;
}
else Insert((q.d[key[rt]] < tree[rt].d[key[rt]] ? lc[rt] : rc[rt]), P ^ 1);
pushup(rt);
}
void query(int rt)
{
if(!rt) return;
int dist = dis(q, tree[rt]);
if(dist < ans)
{
ans = dist;
}
int dl = fx(lc[rt]), dr = fx(rc[rt]);
if(dl < dr)
{
if(dl < ans) query(lc[rt]);
if(dr < ans) query(rc[rt]);
}
else
{
if(dr < ans) query(rc[rt]);
if(dl < ans) query(lc[rt]);
}
}
int main()
{
N = read(); M = read();
for(int i=1; i<=N; i++)
{
a[i].In();
a[i].id = i;
b[i] = a[i];
}
build(root, 1, N, 0);
tot = N;
for(int i=1, op; i<=M; i++)
{
op = read();
q.In(); q.id = N + i;
if(op == 1)
{
Insert(root, 0);
}
else
{
ans = INF;
query(root);
printf("%d\n", ans);
}
}
return 0;
}