链接
题解
CDQ分治,首先不看加点操作,也即没有修改只有询问,我们首先把原来的每个询问分成四个小问题,分别询问在
(
x
,
y
)
(x, y)
(x,y)的左下,左上,右下,右上的最近距离,四个里面取最小值即可。以左下为例,答案为:
m
i
n
1
≤
i
≤
n
{
(
x
−
x
i
)
+
(
y
−
y
i
)
}
min_{1 \le i \le n} \{(x - x_i) + (y - y_i)\}
min1≤i≤n{(x−xi)+(y−yi)}
也即:
(
x
+
y
)
−
m
a
x
1
≤
i
≤
n
{
x
i
+
y
i
}
,
x
i
≤
x
,
y
i
≤
y
(x + y) - max_{1 \le i \le n} \{x_i + y_i\},x_i \le x,y_i \le y
(x+y)−max1≤i≤n{xi+yi},xi≤x,yi≤y
这个问题属于典型的二维偏序问题,排个序加上树状数组很容易解决。
加上修改操作之后就要用到CDQ分治了,把初始的n个点也看作是加点操作,这样就形成了一个长度为
n
+
m
n+m
n+m的操作序列,操作序列的先后,或者说是时间,是第一维偏序关系,已经是有序的。构造递归函数
s
o
l
v
e
(
l
,
r
)
solve(l, r)
solve(l,r),表示对于
l
l
l到
r
r
r的任意一个询问
k
k
k,计算
l
l
l到
k
−
1
k-1
k−1中的修改对其的影响,递归求解,设
m
i
d
=
(
l
+
r
)
2
mid = \frac {(l+r)}{2}
mid=2(l+r),分别计算
(
l
,
m
i
d
)
(l,mid)
(l,mid)与
(
m
i
d
+
1
,
r
)
(mid+1,r)
(mid+1,r),然后计算
(
l
,
m
i
d
)
(l,mid)
(l,mid)中的修改对
(
m
i
d
+
1
,
r
)
(mid+1,r)
(mid+1,r)的询问的影响,这样就计算出了
s
o
l
v
e
(
l
,
r
)
solve(l, r)
solve(l,r),整体上计算
s
o
l
v
e
(
1
,
m
)
solve(1, m)
solve(1,m)即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define REP(i, n) for (int i = 1; i <= (n); i++)
#define sqr(x) ((x) * (x))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const int maxn = 1000000 + 100;
const int maxm = 20000 + 100;
const int maxt = 35 + 2;
typedef long long LL;
typedef pair<long long, long long> pii;
typedef pair<double, double> pdd;
const LL unit = 1LL;
const int INF = 0x3f3f3f3f;
const LL Inf = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const double inf = 1e15;
const double pi = acos(-1.0);
const LL mod = 1000000007;
struct BIT
{
int n, c[maxn];
void clear()
{
n = 0;
memset(c, 0, sizeof(c));
}
void init(int n)
{
this->n = n;
}
inline int lowbit(int x)
{
return x & -x;
}
void insert(int x, int v)
{
while (x <= n)
{
c[x] = max(c[x], v);
x += lowbit(x);
}
}
int get_max(int x)
{
int Max = -(1 << 30);
while (x > 0)
{
Max = max(Max, c[x]);
x -= lowbit(x);
}
return Max;
}
} bit;
struct Node
{
int x, y, z;
bool operator<(const Node &a) const
{
return (x < a.x) || ((x == a.x) && (y < a.y));
}
} a[maxn], b[maxn];
int n, m, tot;
int ans[maxn];
void calc(int st, int en, int de, int dx, int dy)
{
for (int i = st; i != en; i += de)
{
int y = dy == 1 ? b[i].y : tot - b[i].y;
int tmp = b[i].x * dx + b[i].y * dy;
if (a[b[i].z].z == 1)
bit.insert(y, tmp);
else
ans[b[i].z] = min(ans[b[i].z], abs(tmp - bit.get_max(y)));
}
for (int i = st; i != en; i += de)
{
int y = dy == 1 ? b[i].y : tot - b[i].y;
if (a[b[i].z].z == 1)
for (; y < tot; y += (y & -y))
bit.c[y] = -(1 << 30);
}
}
void cdq_div(int l, int r)
{
int mid = (l + r) >> 1;
if (l < mid)
cdq_div(l, mid);
if (mid + 1 < r)
cdq_div(mid + 1, r);
int t = 0;
for (int i = l; i <= r; i++)
if ((i <= mid && a[i].z == 1) || (i > mid && a[i].z == 2))
b[++t] = a[i], b[t].z = i;
sort(b + 1, b + 1 + t);
calc(1, t + 1, 1, 1, 1), calc(t, 0, -1, -1, -1);
calc(1, t + 1, 1, 1, -1), calc(t, 0, -1, -1, 1);
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
m += n;
for (int i = 1; i <= n; i++)
cin >> a[i].x >> a[i].y, a[i].y++, a[i].z = 1;
for (int i = n + 1; i <= m; i++)
cin >> a[i].z >> a[i].x >> a[i].y, a[i].y++;
for (int i = 1; i <= m; i++)
tot = max(tot, a[i].y);
tot++;
bit.clear(), bit.init(tot);
memset(bit.c, 0xcf, sizeof(bit.c));
memset(ans, 0x3f, sizeof(ans));
cdq_div(1, m);
for(int i = 1; i <= m; i++)
if(a[i].z == 2)
cout << ans[i] << endl;
return 0;
}