题意 : 给你一棵树、树上的每个点都有点权、之后有若干次问询、每次问询给出一个节点编号以及一个整数 X 、问你以给出节点为根的子树中哪个节点和 X 异或最大、输出这个值
分析 :
看到这种树上异或最值的问题
可以考虑使用 Trie 来解决
首先涉及到子树
我们可以利用 DFS 序来构造出每个根的子树
DFS 序有很好的性质、其子树的所有节点必定是序列中连续的一段
那么我们就可以对这个 DFS 序列建立可持久化 Trie
然后通过类似前缀和减法的方式得到问询节点子树表示的区间中
所有数组成的 Trie 、然后通过贪心的方法来得到最大异或值
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; const int maxNode = (maxn<<5); int root[maxn]; int sz[maxNode]; int ch[maxNode][2]; int totNode = 0; int newNode() { totNode++; memset(ch[totNode], 0, sizeof(ch[totNode])); sz[totNode] = 0; return totNode; } inline void Insert(int F, int C, int val) { F = root[F], C = root[C]; for(int i=30; i>=0; i--){ int bit = (val>>i) & 1; if(!ch[C][bit]){ ch[C][bit] = newNode(); ch[C][!bit] = ch[F][!bit]; sz[ ch[C][bit] ] = sz[ ch[F][bit] ]; } C = ch[C][bit], F = ch[F][bit]; sz[C]++; } } int Query(int x, int y, int val) { int ret = 0; for(int i=30; i>=0; i--){ int c = (val>>i) & 1; if(sz[ch[y][!c]] - sz[ch[x][!c]] > 0) ret += (1<<i), y = ch[y][!c], x = ch[x][!c]; else x = ch[x][c], y = ch[y][c]; } return ret; } struct EDGE{ int v, w, nxt; }Edge[maxn]; int Head[maxn], EdgeCnt = 0; int weight[maxn]; inline void Edge_init(int n) { memset(sz, 0, sizeof(sz)); memset(ch, 0, sizeof(ch)); memset(Head, -1, sizeof(Head)); EdgeCnt = 0; } inline void AddEdge(int From, int To, int Weight) { Edge[EdgeCnt].v = To; Edge[EdgeCnt].w = Weight; Edge[EdgeCnt].nxt = Head[From]; Head[From] = EdgeCnt++; } int squ[maxn], squLen = 1; int st[maxn], en[maxn]; void DFS(int v) { st[v] = squLen; squ[squLen++] = v; for(int i=Head[v]; i!=-1; i=Edge[i].nxt){ int Eiv = Edge[i].v; DFS(Eiv); } en[v] = squLen-1; } int main(void) { int n, q; while(~scanf("%d %d", &n, &q)){ squLen = 1; totNode = 0; Edge_init(n); for(int i=1; i<=n; i++) scanf("%d", &weight[i]); for(int i=1; i<=n-1; i++){ int Fa; scanf("%d", &Fa); AddEdge(Fa, i+1, weight[i]); } DFS(1); root[0] = ch[0][0] = ch[0][1] = 0; for(int i=1; i<squLen; i++) root[i] = newNode(); for(int i=1; i<squLen; i++) Insert(i-1, i, weight[squ[i]]); while(q--){ int v, x; scanf("%d %d", &v, &x); printf("%d ", Query(st[v]-1, en[v], x)); } } return 0; }