HDU 6191 01树合并

来源:互联网 发布:劫的面具淘宝 编辑:程序博客网 时间:2024/06/16 14:44

Query on A Tree

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 76    Accepted Submission(s): 31


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,Fn1Fi 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.

2n,q105

0Vi109

1Fin, the root of the tree is node 1.

1un,0x109
 

Output
For each query, just print an integer in a line indicating the largest result.
 

Sample Input
2 21 211 32 1
 

Sample Output
23
 

Source
2017ACM/ICPC广西邀请赛-重现赛(感谢广西大学)
 
题意:给出一棵树,每个节点有权值,有q次询问,询问的时候给出一个节点编号 u 和一个值 x ,要求你求出u的子树中与 x 的异或值最大的值。

思路:离线存下询问。每个节点建立一棵01字典树,然后从根节点开始,对于这个节点的询问,去计算最大值,然后把叶子节点与它的父亲节点合并成一个树,然后再做该层的询问。

#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<iostream>#include<algorithm>#include<string.h>#include<vector>using namespace std;#define maxn 100005typedef struct tree{tree *nxt[2];}tree;typedef struct {int x; int id;}res;tree *root[maxn]; vector<int>vec[maxn];vector<res>Q[maxn];int val[maxn],ans[maxn];void Update(tree *q,int a){int now;tree *p = q;for(int i = 29;i >= 0;i--){now = 0;if(a & (1 << i)) //判断当前位是0还是1 now = 1;if(p->nxt[now] == NULL){tree *tmp = new tree;tmp->nxt[0] = tmp->nxt[1] = NULL;p->nxt[now] = tmp;}p = p->nxt[now];}}int Query(tree *q,int a){int now;int tmp = 0;tree *p = q;for(int i = 29;i >= 0;i--){now = 0;if(a & (1 << i)) //判断当前为 now = 1;if(p->nxt[now ^ 1] != NULL){// now ^ 1 = 0 则 now 为 1 ,它最佳匹配是 0 ,这里贪心 p = p->nxt[now ^ 1];tmp |= (1 << i);//贪心的结果就是使它成为 1  }else{p = p->nxt[now];}}return tmp;}tree* Merge(tree *t1,tree *t2){if(t1 == NULL)return t2;if(t2 == NULL)return t1;t1->nxt[0] = Merge(t1->nxt[0],t2->nxt[0]);t1->nxt[1] = Merge(t1->nxt[1],t2->nxt[1]);free(t2);return t1;}void Delete(tree *q){if(q->nxt[0])Delete(q->nxt[0]);if(q->nxt[1])Delete(q->nxt[1]);free(q);}void Run(int u){int v;root[u] = new tree;//建树 root[u]->nxt[1] = root[u]->nxt[0] = NULL;Update(root[u],val[u]);//上传树的指针和值,从根节点开始 printf("u = %d  val[u] = %d\n",u,val[u]); for(int i = 0;i < vec[u].size();i++){v = vec[u][i];//找到它的 儿子 Run(v);//儿子建树 root[u] = Merge(root[u],root[v]);// 合并 u 和 它的子树 }// 从叶子节点开始 for(int i = 0;i < Q[u].size();i++){//对于 u 层的询问,做计算,存答案  ,计算完就与根节点合并 ans[Q[u][i].id] = Query(root[u],Q[u][i].x);}}int main(){int n,q,x,y;res tmp;while(scanf("%d %d",&n,&q) != EOF){memset(ans,0,sizeof(ans));for(int i = 1;i <= n;i++){Q[i].clear();vec[i].clear();scanf("%d",&val[i]);}for(int i = 2;i <= n;i++){scanf("%d",&x);vec[x].push_back(i);// vec[x] 存的是 x 的儿子 }for(int i = 1;i <= q;i++){scanf("%d %d",&y,&x);tmp.x = x; //第 y 层的查询 tmp.id = i;Q[y].push_back(tmp);}Run(1);for(int i = 1;i <= q;i++)printf("%d\n",ans[i]);Delete(root[1]);}return 0;}