题目链接

题意:有一棵树,树根为1,树上的每个结点都有一个数字x。给出Q组询问,每组询问有两个值u,x,代表询问以结点u为根的子树中的某一个数与x的最大异或值。

解法一:dfs序+可持久化字典树。看到子树询问,首先要想到dfs序啦。可以对所有结点按dfs序依次建立可持久化的字典树,字典树上的每个结点除了要保存它的后继结点以外,还要保存这个结点出现的次数num。询问结点u时,对[bg[u],ed[u]]上的字典树的num做差,字典树上剩下的num>0的结点即为可行状态,然后按普通的字典树的查询方法查询就是了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+;
const int M=;
int n,Q,head[N],nxt[N],to[N],val[N],nEdge;
int rt[N],num[N*],go[N*][],nnode;
int bg[N],ed[N],tot;
void AddEdge(int u,int v) {
nxt[nEdge]=head[u],to[nEdge]=v,head[u]=nEdge++;
} int update(int v,int x,int bit) {
int u=++nnode;
num[u]=num[v]+;
if(bit<)return u;
int t=(x>>bit)&;
go[u][t]=update(go[v][t],x,bit-);
go[u][t^]=go[v][t^];
return u;
} void dfs(int u) {
bg[u]=++tot;
rt[tot]=update(rt[tot-],val[u],M);
for(int e=head[u]; ~e; e=nxt[e]) {
int v=to[e];
dfs(v);
}
ed[u]=tot;
} int query(int u,int v,int x,int bit,int now) {
if(bit<)return now;
int t=(x>>bit)&;
if(go[u][t^]-go[v][t^]>)
return query(go[u][t^],go[v][t^],x,bit-,now|(<<bit));
else return query(go[u][t],go[v][t],x,bit-,now);
} int main() {
while(scanf("%d%d",&n,&Q)==) {
memset(head,-,sizeof head);
nEdge=nnode=tot=;
for(int i=; i<=n; ++i)scanf("%d",&val[i]);
for(int i=; i<=n; ++i) {
int u;
scanf("%d",&u);
AddEdge(u,i);
}
rt[]=go[][]=go[][]=num[]=;
dfs();
while(Q--) {
int u,x;
scanf("%d%d",&u,&x);
printf("%d\n",query(rt[ed[u]],rt[bg[u]-],x,M,));
}
}
return ;
}

解法二:离线+字典树合并。可以自底而上来回答询问,每回答完一个结点下的所有子节点的询问,就将这个结点的字典树与它所有子节点的字典树合并。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+;
const int M=;
int n,Q,head[N],nxt[N],to[N],val[N],nEdge;
int rt[N],go[N*][],nnode,ans[N];
struct QUERY {
int x,i;
};
vector<QUERY> qr[N];
void AddEdge(int u,int v) {
nxt[nEdge]=head[u],to[nEdge]=v,head[u]=nEdge++;
} int build(int x,int bit) {
int u=++nnode;
if(bit<)return u;
int t=(x>>bit)&;
go[u][t]=build(x,bit-);
go[u][t^]=;
return u;
} int Merge(int u,int v,int bit) {
if(!u)return v;
if(!v)return u;
if(bit<)return u;
go[u][]=Merge(go[u][],go[v][],bit-);
go[u][]=Merge(go[u][],go[v][],bit-);
return u;
} int query(int u,int x,int bit,int now) {
if(bit<)return now;
int t=(x>>bit)&;
if(go[u][t^])
return query(go[u][t^],x,bit-,now|(<<bit));
else return query(go[u][t],x,bit-,now);
} void dfs(int u) {
for(int e=head[u]; ~e; e=nxt[e]) {
int v=to[e];
dfs(v);
}
for(int e=head[u]; ~e; e=nxt[e]) {
int v=to[e];
rt[u]=Merge(rt[u],rt[v],M);
}
for(int i=; i<qr[u].size(); ++i) {
ans[qr[u][i].i]=query(rt[u],qr[u][i].x,M,);
}
} int main() {
while(scanf("%d%d",&n,&Q)==) {
memset(head,-,sizeof head);
nEdge=nnode=;
for(int i=; i<=n; ++i)qr[i].clear();
for(int i=; i<=n; ++i)scanf("%d",&val[i]);
for(int i=; i<=n; ++i) {
int u;
scanf("%d",&u);
AddEdge(u,i);
}
for(int i=; i<=n; ++i)rt[i]=build(val[i],M);
for(int i=; i<Q; ++i) {
int u,x;
scanf("%d%d",&u,&x);
qr[u].push_back({x,i});
}
dfs();
for(int i=; i<Q; ++i)printf("%d\n",ans[i]);
}
return ;
}

还有一种解法是“可持久化字典树合并”,即父结点继承所有子结点的字典树,继承的方式与字典树合并一样,只不过把两棵树的公共部分开新结点就好,也是在线的,但空间消耗较大。

#define FRER() freopen("i.txt","r",stdin)
#define FREW() freopen("o.txt","w",stdout)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+;
const int M=;
int n,Q,head[N],nxt[N],to[N],val[N],nEdge;
int rt[N],go[N*][],nnode,ans[N];
void AddEdge(int u,int v) {
nxt[nEdge]=head[u],to[nEdge]=v,head[u]=nEdge++;
}
int build(int x,int bit) {
int u=++nnode;
if(bit<)return u;
int t=(x>>bit)&;
go[u][t]=build(x,bit-);
go[u][t^]=;
return u;
} int Merge(int u,int v,int bit) {
if(!u)return v;
if(!v)return u;
if(bit<)return u;
int w=++nnode;
go[w][]=Merge(go[u][],go[v][],bit-);
go[w][]=Merge(go[u][],go[v][],bit-);
return w;
}
int query(int u,int x,int bit,int now) {
if(bit<)return now;
int t=(x>>bit)&;
if(go[u][t^])
return query(go[u][t^],x,bit-,now|(<<bit));
else return query(go[u][t],x,bit-,now);
}
void dfs(int u) {
for(int e=head[u]; ~e; e=nxt[e]) {
int v=to[e];
dfs(v);
}
for(int e=head[u]; ~e; e=nxt[e]) {
int v=to[e];
rt[u]=Merge(rt[u],rt[v],M);
}
} int main() {
while(scanf("%d%d",&n,&Q)==) {
memset(head,-,sizeof head);
nEdge=nnode=;
for(int i=; i<=n; ++i)scanf("%d",&val[i]);
for(int i=; i<=n; ++i) {
int u;
scanf("%d",&u);
AddEdge(u,i);
}
for(int i=; i<=n; ++i)rt[i]=build(val[i],M);
dfs();
for(int i=; i<Q; ++i) {
int u,x;
scanf("%d%d",&u,&x);
printf("%d\n",query(rt[u],x,M,));
}
}
return ;
}

HDU - 6191 Query on A Tree (可持久化字典树/字典树合并)的更多相关文章

  1. HDU 6191 Query on A Tree(可持久化Trie+DFS序)

    Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Othe ...

  2. HDU 6191 Query on A Tree(可持久化Trie)

    题意 \(n\) 个点的有根树,根为 \(1\) .每个点有点权,有 \(q\) 个询问,每次询问以 \(u\) 为根的子树的点的点权中异或 \(x\) 所得的最大值是多少. 思路 求出整棵树的 \( ...

  3. [hdu 6191] Query on A Tree

    Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Othe ...

  4. HDU 6191 Query on A Tree(字典树+离线)

    Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Othe ...

  5. HDU 6191 Query on A Tree ( 2017广西邀请赛 && 可持久化Trie )

    题目链接 题意 : 给你一棵树.树上的每个点都有点权.之后有若干次问询.每次问询给出一个节点编号以及一个整数 X .问你以给出节点为根的子树中哪个节点和 X 异或最大.输出这个值 分析 : 看到这种树 ...

  6. HDU 6191 2017ACM/ICPC广西邀请赛 J Query on A Tree 可持久化01字典树+dfs序

    题意 给一颗\(n\)个节点的带点权的树,以\(1\)为根节点,\(q\)次询问,每次询问给出2个数\(u\),\(x\),求\(u\)的子树中的点上的值与\(x\)异或的值最大为多少 分析 先dfs ...

  7. HDU 4836 The Query on the Tree lca || 欧拉序列 || 动态树

    lca的做法还是非常明显的.简单粗暴, 只是不是正解.假设树是长链就会跪,直接变成O(n).. 最后跑的也挺快,出题人还是挺阳光的.. 动态树的解法也是听别人说能ac的.预计就是放在splay上剖分一 ...

  8. QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树

    Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...

  9. HDU 4757 Tree 可持久化字典树 trie

    http://acm.hdu.edu.cn/showproblem.php?pid=4757 给出一棵树,每个节点有权值,每次查询节点 (u,v) 以及 val,问 u 到 v 路径上的某个节点与 v ...

随机推荐

  1. python基础深入(元组、字符串、列表、字典)

    python基础深入(元组.字符串.列表.字典) 一.列表 1.追加 >>>list = [1,2,3,4] #用于在列表末尾添加新的对象,只能单个添加,该方法无返回值,但是会修改原 ...

  2. ggplot2学习总结

  3. 主攻ASP.NET.4.5.1 MVC5.0之重生:政府行政网站常用友情链接跳转javascript[干货分享]

    <!-----------------------------------> <script language="JavaScript" type="t ...

  4. 主攻ASP.NET MVC4.0之重生:使用反射获取Controller的ActionResult

    示例代码 public ActionResult TypeOfForName() { Type typeinfo = typeof(CustomerClassController); //typeof ...

  5. awk的输出格式控制:print 和printf

    1.两个函数和若干个内部变量控制awk的输出格式: 两个函数:print和printf 内部变量:OFS:输出的列间隔符,默认为tab;  ORS:输出的行间隔符,默认为\n printf更加自由化, ...

  6. R中的数据重塑函数

    1.去除重复数据 函数:duplicated(x, incomparables = FALSE, MARGIN = 1,fromLast = FALSE, ...),返回一个布尔值向量,重复数据的第一 ...

  7. linux 查看各目录(文件夹)下文件大小

    # 显示总大小(/下全部文件占用大小) du -sh /* | sort -nr # 显示各文件夹的大小(当前文件夹下各文件夹的大小) du --max-depth=1

  8. 使用Navicat连接oracle时出现unsupported server character set ZHS16GBK的解决之道

    原文网址http://blog.mn886.net/chenjianhua/show/ba1dc6f835be403ea159b0a5e2685ff2/index.html ORA-12737:Ins ...

  9. mysql基础(2)-数据处理(mysql+pandas)

    插入语句insert insert  数据表名(字段名...) values(字段值): 例 : insert into new_student values("张"," ...

  10. MapReduce-多个Mapper

    MapReduce的多输入.多mapper 虽然一个MapReduce作业的输入可能包含多个输入文件(由文件glob.过滤器和路径组成),但所有文件都由同一个InputFormat和同一个Mapper ...