hdu6191(树上启发式合并)
hdu6191
题意
给你一棵带点权的树,每次查询 \(u\) 和 \(x\) ,求以 \(u\) 为根结点的子树上的结点与 \(x\) 异或后最大的结果。
分析
看到子树,直接上树上启发式合并,看到异或,上 \(Trie\) 。
这道题就是两个经典的题目结合了一波。
树上启发式合并处理这种需要查询整个子树的题目尤其有用,可以复用大量的信息。
离线查询后,到要查询的结点直接在 \(Trie\) \(01\) 树上跑一下即可。
先去理解一波 树上启发式合并(\(dsu \ on \ tree\)),就会发现这真是一道模板题。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 100;
const int MX = 30;
struct Ex {
int id, x;
};
struct Trie {
int val[MAXN * 30], nxt[MAXN * 30][2], L, root;
int newnode() {
memset(nxt[L], -1, sizeof nxt[L]);
return L++;
}
void init() {
L = 0;
root = newnode();
}
void update(int x, int key) {
int now = root;
for(int i = MX; i >= 0; i--) {
int o = (x >> i) & 1;
if(nxt[now][o] == -1) nxt[now][o] = newnode();
now = nxt[now][o];
val[now] += key;
}
}
int query(int x) {
int res = 0;
int now = root;
for(int i = MX; i >= 0; i--) {
int o = (x >> i) & 1;
if(val[nxt[now][!o]]) {
now = nxt[now][!o];
res |= (1 << i);
} else {
now = nxt[now][o];
}
}
return res;
}
}trie;
vector<Ex> ex[MAXN];
int fa[MAXN], son[MAXN], dep[MAXN], siz[MAXN];
int col[MAXN];
int cnt, head[MAXN];
struct Edge {
int to, next;
}e[MAXN << 1];
void addedge(int u, int v) {
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
void dfs(int u) {
siz[u] = 1; son[u] = 0;
for(int i = head[u]; ~i; i = e[i].next) {
if(e[i].to != fa[u]) {
fa[e[i].to] = u;
dep[e[i].to] = dep[u] + 1;
dfs(e[i].to);
if(siz[e[i].to] > siz[son[u]]) son[u] = e[i].to;
siz[u] += siz[e[i].to];
}
}
}
int n, q;
int vis[MAXN];
int ans[MAXN];
void update(int u, int key) {
trie.update(col[u], key);
for(int i = head[u]; ~i; i = e[i].next) {
if(e[i].to != fa[u] && !vis[e[i].to]) update(e[i].to, key);
}
}
void dfs1(int u, int flg) {
for(int i = head[u]; ~i; i = e[i].next) {
if(e[i].to != fa[u] && e[i].to != son[u]) dfs1(e[i].to, 1);
}
if(son[u]) {
dfs1(son[u], 0);
vis[son[u]] = 1;
}
update(u, 1);
for(int i = 0; i < ex[u].size(); i++) {
ans[ex[u][i].id] = trie.query(ex[u][i].x);
}
if(son[u]) vis[son[u]] = 0;
if(flg) {
update(u, -1);
}
}
int main() {
while(~scanf("%d%d", &n, &q)) {
for(int i = 1; i <= n; i++) {
ex[i].clear();
fa[i] = son[i] = dep[i] = siz[i] = 0;
}
memset(vis, 0, sizeof vis);
memset(ans, 0, sizeof ans);
trie.init();
cnt = 0;
memset(head, -1, sizeof head);
for(int i = 1; i <= n; i++) {
scanf("%d", &col[i]);
}
for(int i = 2; i <= n; i++) {
int u;
scanf("%d", &u);
addedge(u, i);
addedge(i, u);
}
for(int i = 0; i < q; i++) {
int u, x;
scanf("%d%d", &u, &x);
ex[u].push_back(Ex{i, x});
}
dfs(1);
dfs1(1, -1);
for(int i = 0; i < q; i++) {
printf("%d\n", ans[i]);
}
}
return 0;
}