标签:区间 转化 log 可以转化 操作 while const ddn include
可持久字典树。
询问子树可以转化为询问一段区间,因此可以对树的$dfs$序进行操作。因为是在一群数字中找一个数字和已知数字异或最大,所以可以想到字典树。保存前缀字典树,然后询问区间$[L,R]$的时候,只要$R$的字典树减去$L-1$的字典树就是区间$[L,R]$上的的数字构成的字典树。
#include <bits/stdc++.h> using namespace std; const int maxn = 100000 + 10; int n, a[maxn]; int sz, h[maxn], to[maxn], nx[maxn]; int L[maxn], R[maxn]; int num, b[2 * maxn]; int q; struct Node { int son[2]; int cnt; }s[65 * maxn]; int root[2 * maxn]; void addedge(int u, int v) { to[sz] = v; nx[sz] = h[u]; h[u] = sz; sz ++; } void dfs(int x) { b[++ num] = a[x]; L[x] = num; for(int i = h[x]; i != -1; i = nx[i]) { dfs(to[i]); } b[++ num] = a[x]; R[x] = num; } int addnode() { num ++; s[num].son[0] = -1; s[num].son[1] = -1; s[num].cnt = 0; return num; } int work(int x, int y) { int res = 0; int p1 = root[L[x] - 1]; int p2 = root[R[x]]; for(int i = 30; i >= 0; i --) { int u = (1 << i) & y; u = u ? 1 : 0; if(p1 == -1) { if(s[p2].son[u ^ 1] != -1) { res = res + (1 << i); p2 = s[p2].son[u ^ 1]; } else { p2 = s[p2].son[u]; } } else { if(s[p2].son[u ^ 1] == -1) { p1 = s[p1].son[u]; p2 = s[p2].son[u]; } else { if(s[p1].son[u ^ 1] == -1) { res = res + (1 << i); p1 = s[p1].son[u ^ 1]; p2 = s[p2].son[u ^ 1]; } else { if(s[s[p1].son[u ^ 1]].cnt < s[s[p2].son[u ^ 1]].cnt) { res = res + (1 << i); p1 = s[p1].son[u ^ 1]; p2 = s[p2].son[u ^ 1]; } else { p1 = s[p1].son[u]; p2 = s[p2].son[u]; } } } } } return res; } int main() { while(~scanf("%d%d", &n, &q)) { num = sz = 0; for(int i = 1; i <= n; i ++) { h[i] = -1; } for(int i = 1; i <= n; i ++) { scanf("%d", &a[i]); } for(int i = 1; i <= n - 1; i ++) { int x; scanf("%d", &x); addedge(x, i + 1); } dfs(1); num = 0; root[0] = 0; s[0].son[0] = -1; s[0].son[1] = -1; s[0].cnt = 0; for(int i = 1; i <= 2 * n; i ++) { root[i] = addnode(); int p1 = root[i - 1]; int p2 = root[i]; s[p2].son[0] = s[p1].son[0]; s[p2].son[1] = s[p1].son[1]; s[p2].cnt = s[p1].cnt; for(int j = 30; j >= 0; j --) { int x = (1 << j) & b[i]; x = x ? 1 : 0; if(p1 == -1) { int id = addnode(); s[id].cnt ++; s[p2].son[x] = id; p2 = id; } else { p1 = s[p1].son[x]; int id = addnode(); if(p1 != -1) { s[id].son[0] = s[p1].son[0]; s[id].son[1] = s[p1].son[1]; } if(p1 != -1) { s[id].cnt = s[p1].cnt + 1; } else { s[id].cnt = 1; } s[p2].son[x] = id; p2 = id; } } } for(int i = 1; i <= q; i ++) { int x, y; scanf("%d%d", &x, &y); int ans = work(x, y); printf("%d\n", ans); } } return 0; }
标签:区间 转化 log 可以转化 操作 while const ddn include
原文地址:http://www.cnblogs.com/zufezzt/p/7492847.html