[博客迁移20190713]题解 P4169 【[Violet]天使玩偶/SJY摆棋子】

《算法竞赛》书上例题(可惜原书没代码

天使玩偶,一道好题。(书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*/


cdq大法吼,谢谢兹磁!!!

posted @   EternalEpic  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示