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;
}

浙公网安备 33010602011771号