zoukankan      html  css  js  c++  java
  • 题解-[Violet]天使玩偶/SJY摆棋子

    本蒟蒻先想了一个naive的(O(nlog^3{n}))做法。

    看到求最小值可以想到先二分答案,然后用一个“集体二分”(我也不知道是什么鬼就是一起做二分,然后每个询问的二分上下界都不同)的方法可以一起二分,二分到一个答案后只需统计这个范围内有没有点即可。这时我们可以把曼哈顿距离转成切比雪夫距离,然后就套一个cdq的模板就做完了。可以证明每次cdq的时间复杂度为 (O(nlog^2{n})),然后外层有 (O(log{n})) 次循环,所以总时间复杂度为耻辱的 (O(nlog^3{n}))

    显然是过不去的。考虑换一种思路,不二分。

    这时处理曼哈顿距离的第二种套路:拆绝对值。加上偏序关系后就可以把绝对值拆开了,对应四种关系,对于每种用一个cdq来求即可。这里cdq不再是计数,而是统计一个最大值,具体看代码。

    这里还是举个栗子:假设我们拆开是这样的 (|x1-x2|+|y1-y2|=(x1+y1)-(x2+y2)),那么我们只需维护 (x2+y2) 的最大值即可。这个用树状数组也可以维护。

    考虑其他偏序关系,只需改变偏序关系即可(不用搞什么坐标轴旋转一坨迷惑行为)。

    这题卡常,所以最好把O2带上(我也不知道O2为什么会快这么多)。

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXV = 1000010;
    const int inf = 0x3f3f3f3f;
    struct node{
    	int x, y, val, id, ans;
    }p[1000005], tmp[1000005], q[1000005];
    int ans[1000005];
    int n, m, tot, cnt;
    int BIT[1000055];
    int dx[5] = {0, 1, 1, -1, -1};
    int dy[5] = {0, 1, -1, 1, -1};
    int ask(int x) {
    	int ret = -inf;
    	while (x) {
    		ret = max(ret, BIT[x]);
    		x -= (x & (-x));
    	}
    	return ret;
    }
    void add(int x, int v) {
    	while (x <= MAXV) {
    		BIT[x] = max(BIT[x], v);
    		x += (x & (-x));
    	}
    }
    void del(int x) {
    	while (x <= MAXV) {
    		BIT[x] = -inf;
    		x += (x & (-x)); 
    	}
    }
    bool cmp(int id, int x1, int x2) {
    	if (id <= 2) return x1 > x2;
    	return x1 < x2;
    }
    void cdq(int id, int l, int r) {
    	if (l == r) return;
    	int mid = (l + r) >> 1;
    	cdq(id, l, mid); cdq(id, mid + 1, r);
    	int i = l, j = mid + 1, top = 0;
    	while (i <= mid && j <= r) {
    		if (cmp(id, p[i].x, p[j].x)) {
    			if (id & 1) p[j].ans = min(p[j].ans, p[j].x * dx[id] + p[j].y * dy[id] - ask(p[j].y + 1));
    			else p[j].ans = min(p[j].ans, p[j].x * dx[id] + p[j].y * dy[id] - ask(MAXV - p[j].y - 1));
    			tmp[++top] = p[j++];
    		} else {
    			if (!p[i].val) {
    				tmp[++top] = p[i++];
    				continue;
    			}
    			if (id & 1) add(p[i].y + 1, p[i].x * dx[id] + p[i].y * dy[id]);
    			else add(MAXV - p[i].y - 1, p[i].x * dx[id] + p[i].y * dy[id]);
    			tmp[++top] = p[i++];
    		}
    	}
    	while (i <= mid) {
    		if (!p[i].val) {
    			tmp[++top] = p[i++];
    			continue;
    		}
    		if (id & 1) add(p[i].y + 1, p[i].x * dx[id] + p[i].y * dy[id]);
    		else add(MAXV - p[i].y - 1, p[i].x * dx[id] + p[i].y * dy[id]);
    		tmp[++top] = p[i++];
    	}
    	while (j <= r) {
    		if (id & 1) p[j].ans = min(p[j].ans, p[j].x * dx[id] + p[j].y * dy[id] - ask(p[j].y + 1));
    		else p[j].ans = min(p[j].ans, p[j].x * dx[id] + p[j].y * dy[id] - ask(MAXV - p[j].y - 1));
    		tmp[++top] = p[j++];
    	}
    	for (int now = l; now <= mid; now++) {
    		if (!p[now].val) continue;
    		if (id & 1) del(p[now].y + 1);
    		else del(MAXV - p[now].y - 1);
    	}
    	for (int now = 1; now <= top; now++) p[l + now - 1] = tmp[now];
    }
    int main() {
    	memset(BIT, -inf, sizeof(BIT));
    	memset(ans, inf, sizeof(ans));
    	scanf("%d%d", &n, &m); tot = n;
    	for (int i = 1; i <= n; i++) scanf("%d%d", &p[i].x, &p[i].y), p[i].val = 1;
    	while (m--) {
    		int opt, x, y;
    		scanf("%d%d%d", &opt, &x, &y);
    		if (opt == 1) p[++tot] = node{x, y, 1, 0, 0};
    		else p[++tot] = node{x, y, 0, ++cnt, 0};
    	}
    	for (int i = 1; i <= tot; i++) p[i].ans = inf;
    	for (int i = 1; i <= tot; i++) q[i] = p[i];
    	cdq(1, 1, tot);
    	for (int i = 1; i <= tot; i++) ans[p[i].id] = min(ans[p[i].id], p[i].ans);
    	for (int i = 1; i <= tot; i++) p[i] = q[i];
    	cdq(2, 1, tot);
    	for (int i = 1; i <= tot; i++) ans[p[i].id] = min(ans[p[i].id], p[i].ans);
    	for (int i = 1; i <= tot; i++) p[i] = q[i];
    	cdq(3, 1, tot);
    	for (int i = 1; i <= tot; i++) ans[p[i].id] = min(ans[p[i].id], p[i].ans);
    	for (int i = 1; i <= tot; i++) p[i] = q[i];
    	cdq(4, 1, tot);
    	for (int i = 1; i <= tot; i++) ans[p[i].id] = min(ans[p[i].id], p[i].ans);
    	for (int i = 1; i <= cnt; i++) printf("%d
    ", ans[i]);
    	return 0;
    } 
    
  • 相关阅读:
    Python初学者第十天 集合、十六进制
    Python初学者第九天 字符串、列表、字典练习
    Python初学者第八天 元组和字典
    Python初学者第七天 字符串及简单操作
    Python初学者第六天 列表操作练习
    Python初学者第五天 列表及简单操作
    Python初学者第四天 二进制运转换
    Python初学者第三天 运算符、while循环
    Python初学者第二天 用户输入和注释
    Python初学者第一天 Python安装及第一个Python程序
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/15440249.html
Copyright © 2011-2022 走看看