专栏文章

题解:P12180 DerrickLo's City (UBC002C)

P12180题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipm9y92
此快照首次捕获于
2025/12/03 14:19
3 个月前
此快照最后确认于
2025/12/03 14:19
3 个月前
查看原文

题意

给定一个图,对于每个询问,判断是否存在一个点 pp 使得对于 x[l,r] x \in [l,r]xix_ipp 不经过 xjx_j

思路

我们很容易想到并查集,对于输入的每条边,将编号大的边合并给编号小的边,再用 zkw 线段树维护并查集编号最大值与最小值。每次询问判断两个最值其中一个是否不在 l,rl,r 之间即可。

代码

CPP
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int>PII;
const int MAXN = 1e5 + 5;

int p[MAXN];

struct NODE {
	vector<int> mi, ma;
	int n;

	NODE(int size, int *arr) {
		n = 1;
		while (n < size)
			n <<= 1;
		mi.resize(2 * n, INT_MAX);
		ma.resize(2 * n, INT_MIN);
		for (int i = 0; i < size; i++) {
			mi[i + n] = arr[i + 1];
			ma[i + n] = arr[i + 1];
		}
		for (int i = n - 1; i > 0; i--) {
			mi[i] = min(mi[2 * i], mi[2 * i + 1]);
			ma[i] = max(ma[2 * i], ma[2 * i + 1]);
		}
	}

	PII query(int l, int r) {
		l--;
		r--;
		int rmi = INT_MAX;
		int rma = INT_MIN;
		for (l += n, r += n; l <= r; l >>= 1, r >>= 1) {
			if (l % 2 == 1) {
				rmi = min(rmi, mi[l]);
				rma = max(rma, ma[l]);
				l++;
			}
			if (r % 2 == 0) {
				rmi = min(rmi, mi[r]);
				rma = max(rma, ma[r]);
				r--;
			}
		}
		return {rmi, rma};
	}
};
int n, q;
//int pma[200010];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n >> q;
	for (int i = 1; i <= n; i++)
		p[i] = 0;
	for (int i = 0; i < n - 1; i++) {
		int a, b;
		cin >> a >> b;
		if (a < b) {
			if (p[b] == 0 || p[b] > a)
				p[b] = a;
		} else {
			if (p[a] == 0 || p[a] > b)
				p[a] = b;
		}
	}
	NODE st_min(n, p);
	vector<int> pma(MAXN);
	for (int i = 1; i <= n; i++)
		pma[i] = p[i];
	NODE st_max(n, pma.data());
	while (q--) {
		int l, r;
		cin >> l >> r;
		auto [mip, map] = st_min.query(l, r);
		if (map < l || mip > r) {
			cout << "Yes\n";
			continue;
		}
		int cntp = 0;
		int flag = -1;
		for (int i = l; i <= r; i++) {
			if (p[i] >= l && p[i] <= r) {
				cntp++;
				flag = p[i];
			}
		}
		if (cntp == 0) {
			cout << "Yes\n";
			continue;
		}
		bool valid = true;
		int p1 = flag;
		for (int i = l; i <= r; i++) {
			if (i == p1)
				continue;
			if (p[i] != p1 && (p[i] < l || p[i] > r))
				continue;
			valid = false;
			break;
		}
		if (valid && (p[p1] < l || p[p1] > r)) {
			cout << "Yes\n";
		} else {
			cout << "No\n";
		}
	}

	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...