• 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(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;
    }
    
  • 相关阅读:
    ThreadPoolExecutor线程池参数设置技巧
    函数式接口
    Mac下进入MySQL命令行
    Java8 特性
    Java8 :: 用法 (JDK8 双冒号用法)
    事务传播
    新版IDEA配置tomcat教程(2018)
    Java8 Map的compute()方法
    Spring 普通类与工具类调用service层
    简单工厂(三)——JDK源码中的简单工厂
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13320951.html
Copyright © 2020-2023  润新知