P6224 [BJWC2014]数据 题解
明明是一道 \(\text{k-d tree}\) 模板题,为什么写的人这么少呢。
思路
看到平面上的操作,就必不可免的想到 \(\text{k-d tree}\)。
\(\text{k-d tree}\) 板子大家应该都会写,这里讲一下最近最远的查询。
1.最远
我们可以发现,一个点到一个矩阵的最远距离一定是到其四个角的最大距离,\(\text{k-d tree}\) 维护的矩阵虽然不是一个实际的矩阵,但算出这个答案与原来的答案进行比较,也能剪枝掉不少情况。
2.最近
一个点到一个矩阵的最近距离我们发现,如果点在矩阵内,那么就是零,不然就是直接到边或者到四个角。
为了简便,我们可以这么写:
inline int ask(int x , int y , int id)
{
int res = 0;
res += max(0ll , y - t[id].u) + max(0ll , x - t[id].r);
res += max(0ll , t[id].d - y) + max(0ll , t[id].l - x);
return res;
}
本题实测是不需要方差建树和重构树的,直接交替建树就可以了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200020;
const int inf = 1e10;
int n , m , rt , cnt , top , ans , stk[N];
struct Node
{
int l , r , u , d , siz , a[2] , son[2];
}t[N];
inline int read()
{
int asd = 0 , qwe = 1; char zxc;
while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
return asd * qwe;
}
inline void push_up(int p)
{
t[p].l = t[p].r = t[p].a[0] , t[p].u = t[p].d = t[p].a[1] , t[p].siz = 1;
for(int i = 0;i <= 1;i++) if(t[p].son[i])
t[p].siz += t[t[p].son[i]].siz,
t[p].l = min(t[p].l , t[t[p].son[i]].l) , t[p].r = max(t[p].r , t[t[p].son[i]].r),
t[p].d = min(t[p].d , t[t[p].son[i]].d) , t[p].u = max(t[p].u , t[t[p].son[i]].u);
}
inline void insert(int &p , int id , int opt)
{
if(!p) { p = id , push_up(p); return; }
if(t[id].a[opt] < t[p].a[opt]) insert(t[p].son[0] , id , opt ^ 1);
else insert(t[p].son[1] , id , opt ^ 1); push_up(p);
}
inline void ask1(int p , int x , int y)
{
ans = max(ans , abs(x - t[p].a[0]) + abs(y - t[p].a[1]));
for(int i = 0;i <= 1;i++)
if(t[p].son[i])
{
int l = t[p].l , r = t[p].r , u = t[p].u , d = t[p].d;
int res = max({abs(l - x) + abs(u - y) , abs(r - x) + abs(u - y) , abs(r - x) + abs(d - y) , abs(l - x) + abs(d - y)});
if(res > ans) ask1(t[p].son[i] , x , y);
}
}
inline int ask(int x , int y , int id)
{
int res = 0;
res += max(0ll , y - t[id].u) + max(0ll , x - t[id].r);
res += max(0ll , t[id].d - y) + max(0ll , t[id].l - x);
return res;
}
inline void ask2(int p , int x , int y)
{
ans = min(ans , abs(x - t[p].a[0]) + abs(y - t[p].a[1]));
for(int i = 0;i <= 1;i++)
if(t[p].son[i])
{
int res = ask(x , y , t[p].son[i]);
if(res < ans) ask2(t[p].son[i] , x , y);
}
}
signed main()
{
n = read();
for(int i = 1;i <= n;i++)
{
int x = read() , y = read(); ++cnt;
t[cnt].a[0] = x , t[cnt].a[1] = y;
insert(rt , cnt , 1);
}
m = read();
for(int i = 1;i <= m;i++)
{
int opt = read() , x = read() , y = read();
if(opt == 0)
{
t[++cnt].a[0] = x , t[cnt].a[1] = y;
insert(rt , cnt , 1);
}
if(opt == 1) ans = inf , ask2(rt , x , y) , printf("%lld\n" , ans);
if(opt == 2) ans = -inf , ask1(rt , x , y) , printf("%lld\n" , ans);
}
return 0;
}