CF1479D Odd Mineral Resource

题目大意:

有一棵 \(n\) 个节点的树,每个节点带有一个种类 \(a_i\),有 \(q\) 个询问,每次询问你 \(u_i,v_i,l_i,r_i\),试找到一个种类 \(c_i\),使得其满足:

  • \(l_i\le c_i\le r_i\)
  • \(c_i\) 这个种类在 \(u_i\)\(v_i\) 的简单路径上出现奇数次。

\(n,q\le 3\times 10^5\)

解法:

首先我们考虑怎样判断有种类在 \(u_i\)\(v_i\) 的路径上出现奇数次。我们可以借助异或的特点 \(a⊕a=0\),这样在路径上出现偶数的种类就会被异或掉,从而如果路径异或和 \(>0\),则该路径上有出现奇数次的种类。但是由于会冲突,例如 \(3⊕2⊕1=0\),所以我们要给每个种类随机附上一个值,防止冲突(随机化)。
至于路径的异或和也很好求,直接 \(d_u ⊕ d_v ⊕ val_{lca(u,v)}\)

然后我们考虑怎么使得 \(c\)\([l,r]\) 之间。直接用主席树维护一下,在主席树中二分找一下答案即可。

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const int N = 3e5 + 10, M = 1e7 + 10;
int n, q, a[N];
vector<int> g[N];
ull h[N];
int ls[M], rs[M], rt[M], tot;
ull val[M];
int dep[N], up[N][20];
void insert(int &cur, int pre, int l, int r, int pos, ull h) {
	cur = ++tot;
	ls[cur] = ls[pre]; rs[cur] = rs[pre];
	val[cur] = val[pre] ^ h;
	if(l == r) return;
	int mid = l + r >> 1;
	if(pos <= mid) insert(ls[cur], ls[pre], l, mid, pos, h);
	else insert(rs[cur], rs[pre], mid + 1, r, pos, h);
}
void dfs(int u, int fa) {
	insert(rt[u], rt[fa], 1, n, a[u], h[a[u]]);
	dep[u] = dep[up[u][0] = fa] + 1;
	for(int i = 1; i < 20; i++) up[u][i] = up[up[u][i - 1]][i - 1];
	for(auto v : g[u]) if(v != fa) dfs(v, u);
}
int LCA(int u, int v) {
	if(dep[u] < dep[v]) swap(u, v);
	for(int i = 19; ~i; i--) if(dep[up[u][i]] >= dep[v]) u = up[u][i];
	if(u == v) return u;
	for(int i = 19; ~i; i--) if(up[u][i] != up[v][i]) u = up[u][i], v = up[v][i];
	return up[u][0];
}
int query(int u, int v, int l, int r, int ql, int qr, int lca) {
	if(r < ql || l > qr) return -1;
	if(ql <= l && r <= qr) {
		ull cur = val[u] ^ val[v];
		if(l <= lca && lca <= r) cur ^= h[lca];
		if(cur == 0) return -1;
		if(l == r) return l;
		int mid = l + r >> 1;
		ull lcur = val[ls[u]] ^ val[ls[v]];
		if(l <= lca && lca <= mid) lcur ^= h[lca];
		if(lcur > 0) return query(ls[u], ls[v], l, mid, ql, qr, lca);
		return query(rs[u], rs[v], mid + 1, r, ql, qr, lca);
	}
	int mid = l + r >> 1;
	int res = query(ls[u], ls[v], l, mid, ql, qr, lca);
	if(res != -1) return res;
	return query(rs[u], rs[v], mid + 1, r, ql, qr, lca);
}
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
int main(){
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]), h[i] = rng();
	for(int i = 1; i < n; i++) {
		int u, v; scanf("%d%d", &u, &v);
		g[u].push_back(v); g[v].push_back(u);
	}
	dfs(1, 0);
	while(q--) {
		int u, v, l, r; scanf("%d%d%d%d", &u, &v, &l, &r);
		int lca = LCA(u, v);
		printf("%d\n", query(rt[u], rt[v], 1, n, l, r, a[lca]));
	}
 	return 0;
}
posted @ 2026-07-29 10:54  OIerYang  阅读(5)  评论(0)    收藏  举报