《算法竞赛》书上例题(可惜原书没代码)
天使玩偶,一道好题。(书p243)我就来谈谈自己的想法吧!
而总有人在这种明明可以离线处理的三维偏序问题上投机取巧。
如:KDtree。 蒟蒻想说,KDtree在这题复杂度是不对的。虽有剪枝,可是还是有可能遍历整棵树的(期望复杂度不靠谱)
对上述看法有争议的,请跳转KDtree讨论。觉得自己KDtree复杂度优美的,可以试试这个天使玩偶hack版,对此感谢qqvq大佬的hack数据。
而cdq分治 + bit(树状数组)只要两个log,何乐而不为呢~
cdq不会?三维偏序没学过?树状数组不会用?
那你还是去自闭吧,可以AFO了
开个玩笑,请左转一位大佬博客cdq分治入门到精通
好,那关于这道题,我想说:
先考虑简化版——即不带修改操作
对于每个点,其实是需找左上,左下,右上,右下四个方向最近距离,再取min。
以左下为例:min(1 <= i <= n) {(x - xi) + (y - yi)}
即 x + y - max(1 <= i <= n) {xi + yi} (xi <= x, yi <= y)
四方向类比,用bit维护即可。
考虑待修改,只需再按时间分治。用cdq分治,考虑修改操作在时间轴上对查询操作的影响即可:
cdq:
class rec {
public:
int x, y, z;
inline void Init(int _z, int _x, int _y) {
x = _x; y = _y; z = _z; return;
}
inline bool operator < (const rec&opt) {
return x < opt.x || x == opt.x && y < opt.y;
}
} a[u], b[u];
int tot = 0;
int ans[u], n, m, t;
class BIT {
public:
int c[u];
inline void setup(void) {
Ms(c, 0xcf); return;
}
inline int query(int x) {
int y = inf;
for (; x; x -= lowbit(x)) y = max(y, c[x]);
return y;
}
inline void update(int x, int y) {
for (; x < tot; x += lowbit(x))
chkmax(c[x], y); return;
}
inline void modify(int x) {
for (; x < tot; x += lowbit(x))
c[x] = inf; return;
}
} bit;
inline void calc(int st, int ed, int de, int dx, int dy) {
for (register int i = st; i ^ ed; i += de) {
int y = dy == 1 ? b[i].y : tot - b[i].y;
int tmp = dx * b[i].x + dy * b[i].y;
if (a[b[i].z].z == 1) bit.update(y, tmp);
else chkmin(ans[b[i].z], abs(tmp - bit.query(y)));
}
for (register int i = st; i ^ ed; i += de) {
int y = dy == 1 ? b[i].y : tot - b[i].y;
if (a[b[i].z].z == 1) bit.modify(y);
}
}
inline void cdqdiv(int l, int r) {
int mid = l + r >> 1;
if (l < mid) cdqdiv(l, mid);
if (mid + 1 < r) cdqdiv(mid + 1, r);
t = 0;
for (register 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 + t + 1);
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);
}
全部代码(参考李煜东光盘)如下
CODE:
//Program written by Liu Zhaozhou ~~~
#include <bits/stdc++.h>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <deque>
#include <string>
#define lowbit(x) x & -x
#pragma GCC optimize(3)
using namespace std;
namespace Base {
inline char gc(void)
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
#define gc() getchar()
template <class T> inline void read(T &x)
{
T flag = 1; x = 0; register char ch = gc();
for (; !isdigit(ch); ch = gc()) if (ch == '-') flag = -1;
for (; isdigit(ch); ch = gc()) x = (x << 1) + (x << 3) + (ch & 15);
x *= flag; return;
}
inline int init(void) {
int x; read(x); return x;
}
template <class T> inline void write(T x) {
if (x < 0) putchar('-'), x = -x;
register T y = 1; int len = 1;
for (; y <= x / 10; y *= 10) ++len;
for (; len; --len, x %= y, y /= 10) putchar(x / y + 48);
}
template <class T> inline void writeln(T x) {write(x); puts("");}
template <class T> inline void writeln(T x, char c) {write(x); putchar(c);}
template <class T> inline void writeln(char c, T x) {putchar(c); write(x);}
template <class T> inline void chkmax(T &x, const T y) {x > y ? x = x : x = y;}
template <class T> inline void chkmin(T &x, const T y) {x < y ? x = x : x = y;}
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define Ms(arr, opt) memset(arr, opt, sizeof(arr))
#define Mp(x, y) make_pair(x, y)
inline void file(string str) {
freopen((str + ".in").c_str(), "r", stdin);
freopen((str + ".out").c_str(), "w", stdout);
}
}
using namespace Base;
namespace CDQsolution {
enum {
u = 1000010,
inf = -114783648
};
class rec {
public:
int x, y, z;
inline void Init(int _z, int _x, int _y) {
x = _x; y = _y; z = _z; return;
}
inline bool operator < (const rec&opt) {
return x < opt.x || x == opt.x && y < opt.y;
}
} a[u], b[u];
int tot = 0;
int ans[u], n, m, t;
class BIT {
public:
int c[u];
inline void setup(void) {
Ms(c, 0xcf); return;
}
inline int query(int x) {
int y = inf;
for (; x; x -= lowbit(x)) y = max(y, c[x]);
return y;
}
inline void update(int x, int y) {
for (; x < tot; x += lowbit(x))
chkmax(c[x], y); return;
}
inline void modify(int x) {
for (; x < tot; x += lowbit(x))
c[x] = inf; return;
}
} bit;
inline void calc(int st, int ed, int de, int dx, int dy) {
for (register int i = st; i ^ ed; i += de) {
int y = dy == 1 ? b[i].y : tot - b[i].y;
int tmp = dx * b[i].x + dy * b[i].y;
if (a[b[i].z].z == 1) bit.update(y, tmp);
else chkmin(ans[b[i].z], abs(tmp - bit.query(y)));
}
for (register int i = st; i ^ ed; i += de) {
int y = dy == 1 ? b[i].y : tot - b[i].y;
if (a[b[i].z].z == 1) bit.modify(y);
}
}
inline void cdqdiv(int l, int r) {
int mid = l + r >> 1;
if (l < mid) cdqdiv(l, mid);
if (mid + 1 < r) cdqdiv(mid + 1, r);
t = 0;
for (register 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 + t + 1);
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);
}
}
using namespace CDQsolution;
signed main(void) {
file("cdq");
read(n); read(m); m += n;
for (int i = 1; i <= n; i++)
read(a[i].x), read(a[i].y), a[i].y++, a[i].z = 1;
for (int i = n + 1; i <= m; i++)
read(a[i].z), read(a[i].x), read(a[i].y), a[i].y++;
for (int i = 1; i <= m; i++)
chkmax(tot, a[i].y);
tot++; bit.setup(); Ms(ans, 0x3f);
cdqdiv(1, m);
for (int i = 1; i <= m; i++)
if (a[i].z == 2) writeln(ans[i]);
return 0;
}
/*cdq*/