AcWing:Trie树
创始人
2024-06-02 21:42:22
0

Trie树

用于高效地存储和查找字符串集合的数据结构。

一般用到trie树的地方,字符串:要么全是小写字母、要么全是大写字母、要么是数字(0、1).....

总之字符的数量不会很多。

创建trie树的过程:

如果有一系列字符串:"abcdef", "abdef", "aced", "bcdf".....

设置一个根节点,我们以"abcdef"为例,从根节点开始,遍历根节点的子节点,查找里面是否有"a",如果没有就创建一个,如果有就找到这个节点;然后继续查找"a"节点的根节点有没有"b",如果没有就创建一个,如果有就找到这个节点....直到遍历完整个字符串,然后在最后一个节点上打一个标记,表示这个地方是某一个单词的结尾。

那么trie数有什么用呢?

它可以高效的查找某个字符串是否出现过以及出现过多少次。

AcWing 835. Trie字符串统计

#include using namespace std;const int N = 100010;
// idx表示下标,根节点和空节点的下标均为0;cnt[N]数组用于存放终点字符的数量
// son[N][26]表示每个节点最多可能有26个根节点
int son[N][26], cnt[N], idx, n;
char str[N];void insert(char str[]){int p = 0;// 遍历字符串for(int i = 0; str[i]; i++){int u = str[i] - 'a';if(!son[p][u]) son[p][u] = ++idx;p = son[p][u];}cnt[p]++;
}int quiry(char str[]){int p = 0;for(int i = 0; str[i]; i++){int u = str[i] - 'a';if(!son[p][u]) return 0;p = son[p][u];}return cnt[p];
}int main(){scanf("%d", &n);while(n--){char op[2];scanf("%s %s", op, str);if(op[0] == 'I') insert(str);else printf("%d\n", quiry(str));}return 0;
}

AcWing 143. 最大异或对

暴力

#include using namespace std;const int N = 100010;
int a[N];
int res, n;int main(){scanf("%d", &n);for(int i = 0; i < n; i++){scanf("%d", &a[i]);}for(int i = 0; i < n; i++){for(int j = 0; j < i; j++){res = max(res, a[i] ^ a[j]);}}printf("%d", res);
}

毫无疑问超时,需要优化至O(nlogn)。

内层循环是在固定a[i]后,从a[0]到a[i-1]中找到一个与a[i]异或值最大的一个数。

再来看本题的数据范围,每一个数都是小于2^31,所以都可以看成一个长度为31位的二进制串。

现在假设我们有一个长度为31的二进制串:

111011100......1
|<----31------>|
要想找到异或的最大值,那么最高位越大则越大,所以a[j]最高位为0所得的异或的值一定比最高位为1的异或的值要大
于是我们就只关心最高位为0的a[j]值,然后以此类推再找第二高位为[0]的a[j]值....
这样就完成了剪枝优化操作(贪心)
在trie中每次都向与a[i]字符串字符不同的分支上走即可

于是现在时间复杂度就从10^5 * 10^5 ---> 31 * 10^5

#include using namespace std;const int N = 100010, M = 31 * N;
int a[N];
int n, son[M][2], idx;void insert(int x){int p = 0;for(int i = 30; i >= 0; i--){int u = x >> i & 1;if(!son[p][u]) son[p][u] = ++idx;p = son[p][u];}
}int quiry(int x){int p = 0, res = 0;for(int i = 30; i >= 0; i--){int u = x >> i & 1;if(son[p][!u]){p = son[p][!u];res = res * 2 + !u;} else{p = son[p][u];res = res * 2 + u;}}return res;
}int main(){scanf("%d", &n);for(int i = 0; i < n; i++){scanf("%d", &a[i]);}int res = 0;for(int i = 0; i < n; i++){insert(a[i]);int t = quiry(a[i]);res = max(res, a[i] ^ t);}printf("%d\n", res);return 0;
}

AcWing 3485. 最大异或和

要求子数组的异或和,即为子数组中所有元素按位异或得到的结果。

异或的重要性质:

s = a ^ b ---> a = s ^ b;
有一个数组:
|___________|_________|________|
0           L         R        n
要求L到R的元素的异或和,那么只需求:
从第0个元素到第L-1个元素的异或和s_L-1 = a1 ^ a2 ^ ... ^ aL-1
从第0个元素到第R个元素的异或和s_R = a1 ^ a2 ^ ... ^ aR
则从L到R的元素的异或和sum = s_L-1 ^ s_R
相当于从1 - L-1异或一遍,再从1 - R异或一遍,同一个数异或两次就抵消了:0^0=0, 1^1=0
所以从0 - L-1的数就全为零,得到的sum值即为从L-R的异或和

于是本题相当于维护一个滑动窗口内的trie树,引入一个变量来记录每个节点的数量,每次添加元素时就当前路径上所有节点数量加一,每次删除元素时就当前路径上所有节点数量减一,最少为0。

#include using namespace std;const int N = 100010 * 31;
int son[N][2], cnt[N], idx;
int n, m, s[N];void insert(int x, int v){int p = 0;for(int i = 30; i >= 0; i--){int u = x >> i & 1;if(!son[p][u]) son[p][u] = ++idx;p = son[p][u];cnt[p] += v;}
}int quiry(int x){int res = 0, p = 0;for(int i = 30; i >=0; i--){int u = x >> i & 1;if(cnt[son[p][!u]]){p = son[p][!u];res = 2 * res + 1;}else{p = son[p][u];res = 2 * res;}}return res;
}int main(){scanf("%d %d", &n, &m);for(int i = 1; i <= n; i++){int x;scanf("%d", &x);s[i] = s[i - 1] ^ x;}int res = 0;insert(s[0], 1);for(int i = 1; i <= n; i++){if(i - m - 1 >= 0)insert(s[i - m - 1], -1);res = max(res, quiry(s[i]));insert(s[i], 1);}printf("%d\n", res);return 0;
}

相关内容

热门资讯

安卓系统怎么删除小红标,安卓系... 手机里的小红标是不是让你觉得有点碍眼呢?别急,今天就来教你怎么轻松地把它从安卓系统中删除掉,让你的手...
安卓系统播放路由器,打造无缝网... 你有没有想过,家里的安卓系统设备想要畅快地享受网络,其实只需要一个小小的助手——那就是路由器!今天,...
基于安卓系统的人脸识别,人脸识... 你有没有想过,在手机解锁的时候,只需轻轻一瞥,就能瞬间解锁?这就是基于安卓系统的人脸识别技术的魅力所...
1km安卓系统下载,高效便捷的... 你有没有想过,手机系统升级竟然也能成为一场说走就走的旅行?没错,今天就要带你领略如何轻松下载1km安...
安卓系统手机最好的手机,揭秘年... 你有没有想过,在这个科技飞速发展的时代,拥有一部性能卓越的安卓系统手机是多么重要的事情呢?想象每天都...
安卓手机带苹果系统,跨界融合的... 你有没有想过,如果安卓手机突然穿上了苹果系统的外衣,会是怎样的景象呢?想象那会是怎样的操作体验,又会...
安卓系统nfc哪款好,盘点几款... 你有没有想过,你的安卓手机里藏着一个小秘密——NFC功能?没错,就是那个可以让你轻松刷公交卡、支付购...
安卓系统怎么刷成原生,轻松刷成... 你有没有想过,你的安卓手机其实可以焕然一新,就像刚从工厂里出来一样?没错,就是那种原生安卓的感觉,流...
rk安卓系统启动流程,从点亮屏... 亲爱的读者,你是否曾经好奇过,当你的安卓手机从沉睡中苏醒,那绚丽的界面是如何一步步展现在你眼前的?今...
小米手环要求安卓系统吗,安卓系... 你有没有发现,最近小米手环成了朋友圈的热门话题呢?不少朋友都在讨论,小米手环到底是不是要求安卓系统呢...
电视里是安卓系统,电视系统中的... 你有没有想过,电视里竟然也能用安卓系统?没错,你没听错,就是那个我们平时在手机上使用的安卓系统,现在...
怎么安装安卓魅族系统,体验流畅... 你有没有想过,给手机换换口味,试试安卓魅族系统呢?这可不是什么难事,只要跟着我一步步来,保证让你的手...
安卓系统账号怎么改,轻松实现账... 你是不是也和我一样,在使用安卓手机的时候,突然觉得账号名字太老土了,想要来个焕然一新的改变呢?别急,...
离线语音系统安卓版下载,随时随... 你有没有想过,在手机上也能实现语音助手的功能,而且完全不需要联网?没错,就是那种离线语音系统,听起来...
华为os系统是基于安卓系统吗,... 你有没有想过,华为的手机里那个神秘的OS系统,它是不是就是安卓系统呢?别急,今天就来揭开这个谜底,让...
各品牌安卓系统多大,探索各大品... 你有没有想过,那些我们每天离不开的安卓手机,它们背后的系统到底有多大呢?这可不是一个小问题哦,因为系...
不是安卓系统电视机,探索非安卓... 你有没有想过,家里的电视是不是安卓系统呢?现在市面上,安卓系统电视机可是越来越流行了。但是,你知道吗...
谷歌安卓系统开源免费用,免费体... 你知道吗?在科技的世界里,有时候最让人惊喜的就是那些免费又好用的东西。今天,就让我来给你揭秘一个超级...
安卓电脑版怎么装系统,轻松实现... 你有没有想过,你的安卓电脑版突然间卡得像蜗牛一样,慢得让人抓狂?别急,今天就来教你怎么给它来个焕然一...
安卓系统有几种语音,揭秘多样化... 你知道吗?安卓系统里的语音功能可真是让人爱不释手呢!想象你只需要动动嘴,就能完成各种操作,是不是觉得...