题解:CF1479D Odd Mineral Resource

题意:很简单了,不再赘述。

做法:

首先看到仅出现奇数次很容易想到异或,但是直接异或很容易冲突,所以我们直接给每种颜色赋权即可,在 \(V=2^{64}\) 时错误概率仅为 \(2^{-64}\)

那么我们直接用主席树维护每个节点到根上颜色在一个区间内的异或和,在主席树上二分,每次如果左区间异或和不是 0 就往左走,否则往右走。如果当前区间异或和为 0 那么认为答案是 0。

一点实现细节:注意到 \(w_x\oplus w_y \oplus v_{c_{lca(x, y)}}\),其中 \(v_c\) 是颜色 \(c\) 随机映射的权值。在主席树上二分时只用传入这些东西即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 3e5 + 5, bs = 131, mod[2] = {998244353, 1000000000 + 7};
mt19937_64 rnd(time(0));
int n, m, c[maxn], rt[maxn], val[maxn];
struct node {
	int l, r, res;
};
struct Segtree {
	node tr[maxn * 50];
	int tot;
	void pushup(int t) {
		tr[t].res = tr[tr[t].l].res ^ tr[tr[t].r].res;
	}
	int modify(int l, int r, int pos, int p, int q) {
		p = ++tot, tr[p] = tr[q];
		if(l == r) {
			tr[p].res ^= val[l];
			return p;
		}
		int mid = l + r >> 1;
		if(pos <= mid)
			tr[p].l = modify(l, mid, pos, tr[p].l, tr[q].l);
		else
			tr[p].r = modify(mid + 1, r, pos, tr[p].r, tr[q].r);
		pushup(p);
		return p;
	}
	int query(int l, int r, int x, int y, int a, int b, int c, int d) {
	//	cout << (tr[a].res ^ tr[b].res ^ tr[c].res ^ tr[d].res) << " " << l << " " << r << endl;
		if((tr[a].res ^ tr[b].res ^ tr[c].res ^ tr[d].res) == 0)
			return -1;
		if(l == r)
			return l; 
		int mid = l + r >> 1, res = -1;
		if(x <= mid) {
			res = query(l, mid, x, y, tr[a].l, tr[b].l, tr[c].l, tr[d].l);
			if(res != -1)
				return res;
		}
		if(mid < y)
			res = query(mid + 1, r, x, y, tr[a].r, tr[b].r, tr[c].r, tr[d].r);
		return res;
	}
} tree;
vector<int> e[maxn];
int f[maxn][21], dep[maxn];
void dfs(int u, int fa) {
	rt[u] = tree.modify(1, n, c[u], rt[u], rt[fa]);
	f[u][0] = fa; dep[u] = dep[fa] + 1;
	for (int i = 0; i < e[u].size(); i++) {
		int v = e[u][i];
		if(v == fa)
			continue;
		dfs(v, u);
	}
}
void prepare() {
	for (int j = 1; j <= 20; j++)
		for (int i = 1; i <= n; i++)
			f[i][j] = f[f[i][j - 1]][j - 1];
}
int lca(int x, int y) {
	if(dep[x] < dep[y])
		swap(x, y);
	for (int i = 20; i >= 0; i--)
		if(dep[f[x][i]] >= dep[y])
			x = f[x][i];
	for (int i = 20; i >= 0; i--)
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	return (x == y ? x : f[x][0]);
}
signed main() {
	ios::sync_with_stdio(false);
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> c[i], val[i] = rnd();
	for (int i = 1; i < n; i++) {
		int x, y;
		cin >> x >> y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(1, 0);
	prepare();
	while(m--) {
		int x, y, l, r;
		cin >> x >> y >> l >> r;
		int d = lca(x, y);
	//	cout << d << endl;
		cout << tree.query(1, n, l, r, rt[x], rt[y], rt[d], rt[f[d][0]]) << endl;
	}
	return 0;
}
posted @ 2025-07-25 17:54  LUlululu1616  阅读(11)  评论(0)    收藏  举报