【HDU 6191】Query on A Tree 【可持久化字典树】

题目

给出一棵有n个结点的树,树根是1,每个结点给出一个value。然后给出q个询问,每个询问给出两个整数u和x,你要在以u结点为根的子树中找出一个结点v,使得val[v] xor x最大, 并输出这个最大值

分析

显而易见的可持久化字典树,只不过这次每次查询不是查询一个区间,而是查询一棵子树。那么也很简单,我们只要预处理出dfs序然后找出每个结点以它为根的子树在dfs序中的区间。然后以这个区间建可持久化字典树就可以了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5
 6 using namespace std;
 7 const int maxn=100000+10;
 8 int val[maxn];
 9 int head[maxn],to[maxn],Next[maxn];
10 int n,q,sz;
11 void add_edge(int a,int b){
12     ++sz;
13     to[sz]=b;Next[sz]=head[a];head[a]=sz;
14 }
15 int order[maxn],L[maxn],R[maxn],num;
16 void dfs(int u,int fa){
17     num++;
18     order[num]=val[u];
19     L[u]=num;
20     for(int i=head[u];i!=-1;i=Next[i]){
21         int v=to[i];
22         if(v!=fa)
23             dfs(v,u);
24     }
25     R[u]=num;
26 }
27 int ch[maxn*2*33][2],root[maxn],sum[maxn*2*33][2],cnt,val_t[2*maxn*33];
28 void update(int x,int y,int a,int ID){
29     root[x]=++cnt;x=root[x];
30     for(int i=31;i>=0;i--){
31         int id=(a>>i)&1;
32         sum[x][id]+=sum[y][id]+1;
33         sum[x][!id]+=sum[y][!id];
34         ch[x][!id]=ch[y][!id];
35         ch[x][id]=++cnt;
36         memset(ch[cnt],0,sizeof(ch[cnt]));
37         val_t[cnt]=0;
38         x=ch[x][id];y=ch[y][id];
39     }
40     val_t[x]=ID;
41 }
42 int query(int x,int y,int a){
43     for(int i=31;i>=0;i--){
44         int id=(a>>i)&1;
45         if(sum[x][!id]-sum[y][!id]){
46             x=ch[x][!id],y=ch[y][!id];
47         }else{
48             x=ch[x][id],y=ch[y][id];
49         }
50     }
51     return val_t[x];
52 }
53 int main(){
54     while(scanf("%d%d",&n,&q)!=EOF){
55         sz=0;
56         cnt=0;
57         memset(head,-1,sizeof(head));
58         memset(sum,0,sizeof(sum));
59         for(int i=1;i<=n;i++){
60             scanf("%d",&val[i]);
61         }
62         for(int i=2;i<=n;i++){
63             int a;
64             scanf("%d",&a);
65             add_edge(a,i);
66         }
67         num=0;
68         dfs(1,-1);
69 //        for(int i=1;i<=n;i++)
70 //            printf("%d ",order[i]);
71 //        printf("\n");
72         update(0,0,0,0);
73         for(int i=1;i<=n;i++){
74             update(i,root[i-1],order[i],i);
75         }
76         int u,x;
77         for(int i=1;i<=q;i++){
78             scanf("%d%d",&u,&x);
79             printf("%d\n",order[query(root[R[u]],root[L[u]-1],x)]^x);
80         }
81     }
82 return 0;
83 }

原文地址:https://www.cnblogs.com/LQLlulu/p/9496426.html

时间: 2024-08-28 20:16:03

【HDU 6191】Query on A Tree 【可持久化字典树】的相关文章

hdu 6191 Query on A Tree(dfs序+可持久化字典树)

题目链接:hdu 6191 Query on A Tree 题意: 给你一棵树,每个节点有一个值,现在有q个询问,每个询问 询问一个u x,问以u为根的子树中,找一个节点,使得这个节点的值与x异或的值最大,输出那个最大的值. 题解: dfs序和一棵可持久化字典树就搞定了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=a;i<=b;++i) 4

hdu 4757 Tree(可持久化字典树)

题目链接:hdu 4757 Tree 题目大意:给定一棵树,每一个节点有一个值.如今有Q次询问,每次询问u到v路径上节点值与w亦或值的最大值. 解题思路:刚開始以为是树链剖分,事实上树链剖分仅仅是用来求LCA(能够不用树链剖分). 可持久化字典树.在每次插入的同一时候,不改动原先的节点.而是对全部改动的节点复制一个新的节点,而且在新的节点 上做操作,这样做的目的是可以获取某次改动前的状态.同过可持久化的操作,保留了改动前后的公共数据. 对给定树上的全部节点权值建立01字典树,然后每一个节点都保存

Hdu-4757 Tree(可持久化字典树+lca)

题目链接:点这 我的github地址:点这 Problem Description Zero and One are good friends who always have fun with each other. This time, they decide to do something on a tree which is a kind of graph that there is only one path from node to node. First, Zero will giv

[hdu 6191] Query on A Tree

Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total Submission(s): 733    Accepted Submission(s): 275 Problem Description Monkey A lives on a tree, he always plays on this tree. One day, monkey

2017广西邀请赛 Query on A Tree (可持续化字典树)

Query on A Tree 时间限制: 8 Sec  内存限制: 512 MB提交: 15  解决: 3[提交][状态][讨论版] 题目描述 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 pr

【BZOJ2741】【FOTILE模拟赛】L 可持久化字典树+分块

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44496739"); } 题解: 首先我们处理出来sum[0,n]作为异或前缀和,然后答案就不再是[l,r]中间某段区间的异或和,而转化成求了[l?1,r]中任意两点异或和的最大值. 然后我们分块处理出fi,j表示 [第i块的开头,j

Codeforces 706D Vasiliy&#39;s Multiset(可持久化字典树)

[题目链接] http://codeforces.com/problemset/problem/706/D [题目大意] 要求实现一个集合中的三个操作,1:在集合中加入一个元素x,2:从集合中删除一个元素x(保证x存在),3:要求从集合中选出一个数,使得其与给出的数x的异或值最大,输出这个异或值. [题解] 可以将所有的以二进制形式存在01字典树上,删除即插入权值为-1的二进制串,对于异或值最大的操作,我们只要在字典树上按位贪心,从最高位开始尽量保证该位存在最后就能得到答案.写代码的时候直接写了

codechef Xor Queries (可持久化字典树)

题目链接:codechef Xor Queries 题意: 题解: 一棵可持久化字典树就行了. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 using namespace std; 4 5 const int N=5e5+7; 6 struct Node{int son[2],cnt;}ch[N*40]; 7 int root[N],cnt,ed,n; 8 9 void ins(int

bzoj3166: [Heoi2013]Alo 可持久化字典树

左右两边的比i大的最近的两个值.然后可持久化字典树即可. #include<bits/stdc++.h> using namespace std; int maxn=0,n,root[1600000],a[50010],cnt=0,l[1600000],r[1600000],p1[50010][25],p2[50010][25],sum[1600000],ans=0,pans=0,l1[50010],r1[50010],l2[50010],r2[50010]; void add(int &am