51nod 1702 卡牌游戏(kd-tree)

51nod 1702 卡牌游戏(kd-tree)

题目大意

有一种卡牌游戏,玩家有两个属性x和y——分别表示白魔法技能和黑魔法技能。在桌面上有n张卡牌,每一张卡牌有四个属性 ai, bi, ci, di 。玩家每一步可以选择一张卡牌,但是卡牌要求满足 ai ≤ x 并且 bi ≤ y 。选择了之后,玩家的黑白魔法就会发生变化,即 x = ci 和 y = di 。

游戏刚开始的时候玩家的黑白魔法值都是0。游戏的目的是要拿到第n张卡牌。玩家可以按照任意次序,任意次数去使用这些卡牌。问最少要几步才能拿到第n张卡牌。

数据范围

ai, bi, ci, di (0≤ai,bi,ci,di≤10^9) 1≤n≤100000

解题思路

kd-tree 优化建图即可,我们使用 deque 时所有点只会更新一次,所以不必连边,在 kd-tree 上建图时可以看看当前的子树是否均被更新过,这个剪枝可以大大变快

复杂度大概是 \(\Theta(n\sqrt n)\)

代码

const int N = 200500;
struct Poi {
	int x, y, tx, ty, num;
	void init(int nn) { read(x), read(y), read(tx), read(ty), num = nn; }
}p[N];

bool cmpx(Poi a, Poi b) { return a.x < b.x; }
bool cmpy(Poi a, Poi b) { return a.y < b.y; }

int Lx[N], Rx[N], Ly[N], Ry[N];
void update(int x, int s) {
	Mx(Rx[x], Rx[s]), Mn(Lx[x], Lx[s]);
	Mx(Ry[x], Ry[s]), Mn(Ly[x], Ly[s]); 
}

int son[N][2];
int build(int l, int r, int d) {
	if (l > r) return 0; int mid = (l + r) >> 1;
	if (d) nth_element(p + l, p + mid, p + r + 1, cmpx);
	else nth_element(p + l, p + mid, p + r + 1, cmpy);
	son[mid][0] = build(l, mid - 1, d ^ 1);
	son[mid][1] = build(mid + 1, r, d ^ 1);
	Rx[mid] = Lx[mid] = p[mid].x, Ry[mid] = Ly[mid] = p[mid].y;
	if (son[mid][0]) update(mid, son[mid][0]);
	if (son[mid][1]) update(mid, son[mid][1]);
	return mid;
}

struct node {
	int num, dis;
	node(int n = 0, int d = 0) { num = n, dis = d; }
};
deque<node> q;

int ans[N], n;
inline void Push(int num, int dis, int k) {
	if (ans[num]) return; ans[num] = dis;
	if (k) q.push_back(node(num, dis));
	else q.push_front(node(num, dis));
}

void change(int x, int dis, int lx, int ly) {
	if (!x || ans[x + n]) return;
	if (Rx[x] <= lx && Ry[x] <= ly) return Push(x + n, dis, 1);
	if (!ans[x] && p[x].x <= lx && p[x].y <= ly) Push(x, dis, 1);
	if (Lx[x] > lx || Ly[x] > ly) return;
	change(son[x][0], dis, lx, ly);
	change(son[x][1], dis, lx, ly);
}

int inv[N];
int main() {
	read(n); int rt = (1 + n) >> 1;
	for (int i = 1;i <= n; i++) p[i].init(i);
	build(1, n, 1);
	for (int i = 1;i <= n; i++) 
		if (!(p[i].x | p[i].y)) q.push_back(node(i, ans[i] = 1));
	for (int i = 1;i <= n; i++)
		inv[p[i].num] = i;
	while (q.size()) {
		node x = q.front(); q.pop_front();
		if (x.num > n) {
			int k = x.num - n;
			if (son[k][0]) Push(son[k][0] + n, x.dis, 0); 
			if (son[k][1]) Push(son[k][1] + n, x.dis, 0);
			Push(k, x.dis, 0); if (p[k].num == n) return write(ans[k]), 0;
		}
		else {
			int k = x.num;
			change(rt, x.dis + 1, p[k].tx, p[k].ty);
		}
	}
	write(ans[inv[n]] ? ans[inv[n]] : -1);
	return 0;
}
posted @ 2020-07-16 09:38  Hs-black  阅读(218)  评论(0编辑  收藏  举报