HDU - 6191 Query on A Tree
题意:
给出一个带点权的树。q次询问,每次询问给出u和x,求点u的子树中与x异或的最大值。
题解:
将询问离线化。
每颗节点动态建立字典树。每个节点和自己的孩子合并,但是这样会改变子树节点的字典树,所以就在每个节点回溯的时候计算出该节点的答案。
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; typedef long long ll; const int N = 1e5+5; int n, q; int tot, num, f; int w[N]; int root[N]; int head[N], to[N], nxt[N]; int tre[N*40][2]; int u, x; vector<int> g[N]; vector<int> id[N]; int ans[N]; void build(int id) { scanf("%d", &w[id]); root[id] = ++tot; int c = tot; for(int i = 30; i >= 0; i--) { if(w[id]&(1<<i)) tre[c][1] = ++tot; else tre[c][0] = ++tot; c = tot; } } void update(int u, int v) { if(tre[v][0]>0) { if(tre[u][0]==0) tre[u][0] = tre[v][0]; else update(tre[u][0], tre[v][0]); } if(tre[v][1]>0) { if(tre[u][1]==0) tre[u][1] = tre[v][1]; else update(tre[u][1], tre[v][1]); } } int query(int u, int x) { int res = 0; int c = root[u]; for(int i = 30; i >= 0; i--) { int p = (x>>i)&1; if(tre[c][p^1] > 0) res |= (1<<i), c = tre[c][p^1]; else if(tre[c][p] > 0) c = tre[c][p]; } return res; } void dfs(int u) { for(int i = head[u]; ~i; i = nxt[i]) { dfs(to[i]); update(root[u], root[to[i]]); } int len = g[u].size(); for(int i = 0; i < len; i++) ans[id[u][i]] = query(u, g[u][i]); } int main() { while(~scanf("%d%d", &n, &q)) { tot = num = 0; memset(tre, 0, sizeof(tre)); memset(head, -1, sizeof(head)); for(int i = 1; i <= n; i++) { g[i].clear(); id[i].clear(); } for(int i = 1; i <= n; i++) build(i); for(int i = 2; i <= n; i++) { scanf("%d", &f); to[++num] = i; nxt[num] = head[f]; head[f] = num; } for(int i = 1; i <= q; i++) { scanf("%d%d", &u, &x); g[u].push_back(x); id[u].push_back(i); } dfs(1); for(int i = 1; i <= q; i++) printf("%d\n", ans[i]); } }