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(nsqrt 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;
}