2017 广西邀请赛&& hdu 6191 Query on A Tree(字典树启发式合并)

xiaoxiao2021-02-28  81

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,Fn1 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. 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 2 1 2 1 1 3 2 1   Sample Output 2 3   Source 2017ACM/ICPC广西邀请赛-重现赛(感谢广西大学)

题意:给你一棵树,每次询问一个数与结点u的子树上的结点的值异或的最大值。

要查询一组数和一个数异或的最大值,很轻易可以看出是字典树。(01字典树)

然而每次要查询的是以某一个结点为根的子树上的数值的异或最大值,当然不能建n棵以每一个结点为根的字典树,所以我们用到了启发式合并,这样我们先查询后合并,就可以得到所有查询的答案。

像字典树线段树这种树结构,如果两颗树a,b的结构相同,那么他们就可以合并。(线段树的启发式合并)

#include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn = 1e5 + 10; void tran(char *a,int x) { int i; for(i=0;i<=31;i++) a[i] = '0'; a[i] ='\0'; i = 0; while(x) { a[i++] = (x%2)+'0'; x /= 2; } } struct trie { trie *next[2]; int cnt; trie() { memset(next,0,sizeof(next)); cnt = 0; } }; trie *root[maxn]; void insert(trie *p,int x) { int i,k; char s[33]; tran(s,x); for(i=31;i>=0;i--) { k=s[i]-'0'; if(p->next[k]==NULL) p->next[k]=new trie(); p=p->next[k]; } p->cnt = x; } int query(trie *p,int x,int dir)//dir为1就是往相反的方向走,也就是求最大值 { char s[33]; tran(s,x); for(int i=31;i>=0;i--) { int x = s[i] - '0'; x = x^dir; if(p->next[x] == NULL) x^=1; p = p->next[x]; } return (p->cnt) ^ x; } void del(trie *p) { for(int i=0;i<2;i++) if(p->next[i]!=NULL) del(p->next[i]); free(p); } trie* Merge(trie *a,trie *b) { if(a == NULL) return b; if(b == NULL) return a; a->next[0] = Merge(a->next[0],b->next[0]); a->next[1] = Merge(a->next[1],b->next[1]); free(b); return a; } struct Query { int id,x; Query(int _id,int _x) { id = _id; x = _x; } }; int a[maxn]; vector<int> e[maxn]; vector<Query> q[maxn]; int ans[maxn]; void dfs(int x,int pre) { root[x] = new trie(); insert(root[x],a[x]); for(int i=0;i<e[x].size();i++) { int xx = e[x][i]; if(xx == pre) continue; dfs(xx,x); Merge(root[x],root[xx]); } for(int i=0;i<q[x].size();i++) { ans[q[x][i].id] = query(root[x],q[x][i].x,1); } } int main(void) { int n,m,i,j; while(scanf("%d%d",&n,&m)==2) { for(i=1;i<=n;i++) { e[i].clear(); q[i].clear(); scanf("%d",&a[i]); } for(i=2;i<=n;i++) { int x; scanf("%d",&x); e[x].push_back(i); } for(i=1;i<=m;i++) { int u,x; scanf("%d%d",&u,&x); q[u].push_back(Query(i,x)); } dfs(1,-1); for(i=1;i<=m;i++) printf("%d\n",ans[i]); del(root[1]); } return 0; }

转载请注明原文地址: https://www.6miu.com/read-75101.html

最新回复(0)