Query on A Tree
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 1732 Accepted Submission(s): 566
Problem Description
Monkey A lives on a tree, he always plays on this tree.
One day, monkey A learned about one of the bit-operations, xor. He was keen of this interesting operation and wanted to practise it at once.
Monkey A gave a value to each node on the tree. And he was curious about a problem.
The problem is how large the xor result of number x and one node value of label y can be, when giving you a non-negative integer x and a node label u indicates that node y is in the subtree whose root is u(y can be equal to u).
Can you help him?
Input
There are no more than 6 test cases.
For each test case there are two positive integers n and q, indicate that the tree has n nodes and you need to answer q queries.
Then two lines follow.
The first line contains n non-negative integers V1,V2,⋯,Vn, indicating the value of node i.
The second line contains n-1 non-negative integers F1,F2,⋯Fn−1, Fi means the father of node i+1.
And then q lines follow.
In the i-th line, there are two integers u and x, indicating that the node you pick should be in the subtree of u, and x has been described in the problem.
2≤n,q≤105
0≤Vi≤109
1≤Fi≤n, the root of the tree is node 1.
1≤u≤n,0≤x≤109
Output
For each query, just print an integer in a line indicating the largest result.
Sample Input
2 2 1 2 1 1 3 2 1
Sample Output
2 3
Source
题意:一棵树上,每次输入u x,询问以u为根节点的子树上的某个点与x异或最大可以是多少
题解:树上启发式合并
对于每个节点都搞一个字典树,进行启发式合并即可。
一开始被卡内存了= =,弄了个pool记录废物节点,重复利用下内存就过了。。
时间复杂度O(nlog^2 n)
#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define per(i,a,b) for(int i=(a)-1;i>=(b);--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'<<endl
#define clr(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int mod = 1e9 + 7;
const int MX = 1e5 + 7;
VI E[MX];
int val[MX], ans[MX];
vector<PII> ver[MX];
const int MXM = MX * 31;
int nxt[MXM][2], rear;
int pool[MXM], cnt, tot;
void init(int n) {
rep(i, 1, n + 1) {
E[i].clear();
ver[i].clear();
}
cnt = rear = tot = 0;
}
struct Trie {
int root;
int new_node() {
if(cnt) rear = pool[cnt--];
else rear = ++tot;
memset(nxt[rear], 0, sizeof(nxt[rear]));
return rear;
}
void init() {
root = new_node();
}
void dfs(int u) {
if(nxt[u][0]) dfs(nxt[u][0]);
if(nxt[u][1]) dfs(nxt[u][1]);
pool[++cnt] = u;
}
void del() {
dfs(root);
}
void insert(int x) {
int now = root, tmp;
per(i, 31, 0) {
tmp = x >> i & 1;
if (!nxt[now][tmp]) nxt[now][tmp] = new_node();
now = nxt[now][tmp];
}
}
int query(int x) {
int now = root, tmp, ret = 0;
per(i, 31, 0) {
tmp = x >> i & 1;
if(!nxt[now][tmp ^ 1]) now = nxt[now][tmp];
else {
now = nxt[now][tmp ^ 1];
ret |= 1 << i;
}
}
return ret;
}
} t[MX];
VI son[MX];
void merge(VI& v1, VI& v2, Trie& t1, Trie& t2) {
if(v2.size() > v1.size()) swap(v1, v2), swap(t1, t2);
t2.del();
rep(i, 0, v2.size()) v1.pb(v2[i]);
rep(i, 0, v2.size()) t1.insert(v2[i]);
v2.clear();
}
void dfs(int u) {
son[u].clear(), son[u].pb(val[u]);
t[u].init(), t[u].insert(val[u]);
rep(i, 0, E[u].size()) {
int v = E[u][i];
dfs(v);
merge(son[u], son[v], t[u], t[v]);
}
rep(i, 0, ver[u].size()) ans[ver[u][i].y] = t[u].query(ver[u][i].x);
}
int main() {
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
int n, q, u, v, x;
while(cin >> n >> q) {
init(n);
rep(i, 1, n + 1) scanf("%d", &val[i]);
rep(i, 2, n + 1) {
scanf("%d", &v);
E[v].pb(i);
}
rep(i, 1, q + 1) {
scanf("%d%d", &u, &x);
ver[u].pb(PII(x, i));
}
dfs(1);
rep(i, 1, q + 1) printf("%d\n", ans[i]);
}
return 0;
}