字典树大家都知道吧,如果不知道可以看这里,我的模板写得还是不错的:
字符串–Trie树(字典树)


接下来我们先看一个问题,通过这个问题来了解Xor这个运算的基本性质:
洛谷 P2420 让我们异或吧
题目大意:给定一棵带权树,多次询问两点之间边权异或和。
性质:a^x^x=a,其中^代表Xor运算,证明略。
利用这条性质,我们可以任取一点为根,通过一次dfs算出每个点到根节点的异或和val[u],假设每次询问的点是u,v,则答案就是val[u]^val[v]。
过程:val(u,v)
=val(u,lca)Xor val(v,lca)
=val(u,root)Xor val(lca,root)Xor val(v,root)Xor val(lca,root)
=val(u,root)Xor val(v,root)
此题代码:

//Âå¹È2420 ÈÃÎÒÃÇÒì»ò°É
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
inline int read(){int x=0;char ch=' ';while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x;
}
struct edge{int to,next,w;
}e[200001];
int n,m,tot;
int head[100001];
int v[100001];
int st[100001][20];
int dep[100001];
void dfs(int x,int fa){st[x][0]=fa;for(int i=head[x];i;i=e[i].next){int u=e[i].to;if(u==fa)continue;v[u]=v[x]^e[i].w;dep[u]=dep[x]+1;dfs(u,x);}
}
inline void addedge(int x,int y,int l){e[++tot].to=y;e[tot].next=head[x];e[tot].w=l;head[x]=tot;
}
int main(){n=read();for(int i=1;i<=n-1;i++){int x=read(),y=read(),l=read();addedge(x,y,l);addedge(y,x,l);}dfs(1,0);m=read();for(int i=1;i<=m;i++){int x=read(),y=read();int ans=v[x]^v[y];printf("%d\n",ans);}return 0;
}

接下来就是正题了——如何用字典树来解决Xor问题?
题目链接:Xor Sum
整体思路:Trie树+贪心
我们要选出一个数来使它和另一个数的异或和最大,那么当然要转二进制来看了。
转了二进制之后我们可以发现高位的值比所有低位的值相加还要大,那么就有贪心思路了:
建立一棵01Trie(每个点只有0和1两个儿子),然后将每个初始数字从高位到低位按位插入进来,然后每次查询时每一步尽量走和它那一位不同的方向,最后输出即可。
此题代码:

//hdu4825 Xor Sum
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
inline int read(){int x=0;char ch=' ';while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x;
}
int n,m,tot;
int ch[3100001][2];
int val[3100001];
void insert(int x){int u=0;for(int i=31;i>=0;i--){int c=(x>>i)&1;if(!ch[u][c]){ch[u][c]=++tot;}u=ch[u][c];}val[u]=x;
}
int find(int x){int u=0;for(int i=31;i>=0;i--){int c=(x>>i)&1;if(ch[u][c^1]){u=ch[u][c^1];}else{u=ch[u][c];}}return val[u];
}
int main(){int T=read();int k=1;while(T--){printf("Case #%d:\n",k++);memset(ch,0,sizeof(ch));memset(val,0,sizeof(val));tot=0;n=read();m=read();for(int i=1;i<=n;i++){insert(read());}for(int i=1;i<=m;i++){printf("%d\n",find(read()));}}return 0;
}

接下来我们将第一个问题和第二个问题结合在一起来看一个题;
题目链接:The xor-longest Path
题目大意:给定一棵树,求最大异或路径。
思路:我们可以每次固定一个点,寻找和它异或路径最大的点,更新答案。这时问题就转化成了在树上已知一个点如何找另一个点和它异或路径最大。
结合T1和T2,那么我们可以表示出两点间的异或路径:val(u)^val(v),其中因为我们已经固定了一个点了,那么就是要找一个值和已知值异或值最大了,这就是T2的问题。
方案就很明显了,dfs求出每个点到根节点的异或值,然后将这些值插入到一棵01Trie中,枚举每个点找从这个点出发的最大异或路径,并更新答案。
此题代码:

//poj3764 The xor-longest Path
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int v[100001];
int ch[3100001][2];
int n;
struct edge{int to,next,w;
}e[200001];
int head[100001];
void dfs(int x,int fa){for(int i=head[x];i;i=e[i].next){int u=e[i].to;if(u==fa)continue;v[u]=v[x]^e[i].w;dfs(u,x);}
}
int tot;
inline void addedge(int x,int y,int l){e[++tot].to=y;e[tot].next=head[x];head[x]=tot;e[tot].w=l;
}
void insert(int x){int u=0;for(int i=30;i>=0;i--){int c=(x>>i)&1;if(!ch[u][c]){ch[u][c]=++tot;}u=ch[u][c];}
}
int find(int x){int u=0;int ans=0;for(int i=30;i>=0;i--){int c=(x>>i)&1;if(ch[u][c^1]){ans+=(1<<i);u=ch[u][c^1];}else{u=ch[u][c];}}return ans;
}
int main(){while(scanf("%d",&n)==1){memset(ch,0,sizeof(ch));memset(v,0,sizeof(v));memset(head,0,sizeof(head));tot=0;for(int i=1;i<=n-1;i++){int x,y,l;scanf("%d %d %d",&x,&y,&l);addedge(x,y,l);addedge(y,x,l);}dfs(0,-1);for(int i=0;i<n;i++){insert(v[i]);}tot=0;int ans=0;for(int i=0;i<n;i++){ans=max(ans,find(v[i]));}printf("%d\n",ans);}return 0;
}

转载于:https://www.cnblogs.com/stone41123/p/7581243.html

字典树--Xor问题相关推荐

  1. hdu4825 字典树 XOR

    用字典树思想来做.对于一个数,给出他的二进制,然后更具二进制建立字典树,然后每次询问的时候的数也给出二进制,如果当前为1,那就向0走,为0,向1走. #include<stdio.h> # ...

  2. nyoj 947 Max Xor(字典树)

    Max Xor 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 给一个长度为 n 的数列 {an} ,找出 max {ai ^ aj}. 输入 多组测试数据. 第 1 行 ...

  3. HDU4825 Xor Sum 01字典树(Tire Tree)

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total ...

  4. HDU多校1 - 6955 Xor sum(字典树+贪心)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的序列,要求找到一段长度最短的区间,使得异或和大于等于 kkk,如果有多种答案,输出左端点最小的那个 题目分析:倒着维护一下后缀异或和,将后缀异或 ...

  5. 2014百度之星资格赛—— Xor Sum(01字典树)

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total ...

  6. 【HDOJ6955】Xor sum(异或前缀和,01字典树)

    1006 Xor sum 题意: 给出一个长度为n的序列,求一个最短连续子序列满足异或和大于等于k.n<1e5. 思路: 参考CF665E,求序列a中有多少个异或和大于等于k的子序列,枚举所有的 ...

  7. 【LOJ10050】The XOR Largest Pair(字典树)

    problem 给定n个整数,在其中任意选出两个进行xor运算,得到的结果最大值是多少? n<1e5,ai在int范围内 solution 朴素枚举,O(n^2), TLE 考虑异或运算,相同为 ...

  8. 【CF1616H】Keep XOR Low(字典树)

    题面 题解 为了方便,我们将 xxx 加 1,然后让 aixoraj<xa_i\mathrm{~xor~}a_j<xai​ xor aj​<x . 可以把数插入到字典树中,然后遍历字 ...

  9. 2014百度之星 Xor Sum(字典树+贪心)

    题目在HDU_OJ Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometh ...

最新文章

  1. DeepMind Nando(原牛津大学教授)强化学习最新进展,含图文、公式和代码,附102页PPT下载...
  2. mysql display size_mysql integer size 大小
  3. SQL Server通过动态视图里查找阻塞超过30秒的会话
  4. Requests库的主要方法:requests.request为requests.get和requests.post两个的汇总,只是需要传方法...
  5. 与Selenium的集成测试
  6. windows 2003 英文版支持中文显示、中文输入的设置方法
  7. HIbernate学习笔记5 之 查询
  8. nginx upstream 代理 负载
  9. 【Codeforces 1051D】Bicolorings
  10. Vensim软件中文介绍
  11. mysql表名、字段名命名规范
  12. vue-transition多元素过渡
  13. 【水文】2345——卸载!拜拜了您嘞
  14. 2021-07-12 怎么将桌面图标变大变小
  15. span元素与块级元素(div、p)位于同一行时的垂直居中问题
  16. vue项目使用高德地图
  17. 深入 javascript 之 call函数 用法
  18. “TrueType 造字程序”的具体用法
  19. Python-冒泡排序函数
  20. 想知道手机视频压缩app哪个好用?这几个工具值得一试

热门文章

  1. Jsp+Servlet+JavaBean经典MVC模式理解
  2. Redis Server Memory Optimization
  3. shell中遍历目录
  4. 《巨富们给年轻人的45个忠告》读后感
  5. python list find_一篇文章带你了解Python爬虫常用选择器
  6. XamarinAndroid组件教程RecylerView自定义适配器动画
  7. 桌面笔记工具KeepNote
  8. c语言练习题及答案)(1),c语言练习题(带详解答案)1.pdf
  9. 机器学习(6)--化无限为有限(二)
  10. ios 裁剪框大小_iOS实现裁剪框和图片剪裁功能