Trie树,并查集的简单应用(AcWing)

简介: Trie树,并查集的简单应用(AcWing)

Trie树

Trie 树,也叫“字典树”。顾名思义,它是一个树形结构。它是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。

在每一个单词的结尾需要进行标记,统计个数

现在对上述样例进行模拟

Trie字符串统计

AC代码:

1. #include<iostream>
2. using namespace std;
3. const int N=100010;
4. int son[N][26],cnt[N],idx,m;
5. char str[N];
6. 
7. void insert(char* str)
8. {
9. int p=0;
10. for(int i=0;str[i];i++)
11.     {
12. int u=str[i]-'a';//映射
13. if(!son[p][u]) son[p][u]=++idx;
14.         p=son[p][u];
15.     }
16.     cnt[p]++;//计数
17. }
18. 
19. int find(char* str)
20. {
21. int p=0;
22. for(int i=0;str[i];i++)
23.     {
24. int u=str[i]-'a';
25. if(!son[p][u]) return 0;
26.         p=son[p][u];
27.     }
28. return cnt[p];
29. }
30. 
31. int main(void)
32. {
33. scanf("%d",&m);
34. while(m--)
35.     {
36. char op[5];
37. scanf("%s %s",op,str);
38. if(op[0]=='I')
39.         {
40. insert(str);
41.         }else
42.         {
43. printf("%d\n",find(str));
44.         }
45.     }
46. return 0;
47. }

并查集

并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中。其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。

并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。常常在使用中以森林来表示。

首先创建三个集合,由图可知,每一个点都可以逐级找到自己的祖宗节点,如果祖宗节点相同,那么就是在同一个集合当中,但每一次查找都一个一个找的话效率是十分低效的,因此我们可以采用路径压缩,就是当走完了一个集合之后,我们将这个集合中的所有节点全部指向祖宗节点,那么下一次查找的时间复杂度就是O(1)了,大大提高了查找效率

这个操作可以在递归的过程中实现。

1. int find(int x)
2. {
3. if(p[x]!=x)p[x]=find(p[x]);
4. return p[x];
5. }

之前说到了,判断一个是不是属于同一个集合,就判断他们的祖宗节点是否一样,如果一样,这两个节点就是在同一个集合当中,那么合并A B两个节点,那么我们可以让A节点的祖宗节点设置为B的祖宗节点,那么A B这两个集合就合并了

合并集合

AC代码:

1. #include<iostream>
2. using namespace std;
3. const int N=100010;
4. int p[N],n,m;
5. 
6. int find(int x)
7. {
8. if(p[x]!=x) p[x]=find(p[x]);
9. return p[x];
10. }
11. 
12. int main(void)
13. {
14. scanf("%d %d",&n,&m);
15. for(int i=1;i<=n;i++) p[i]=i;
16. while(m--)
17.     {
18. char op[5];
19. int a,b;
20. scanf("%s",op);
21. if(op[0]=='M')
22.         {
23. scanf("%d %d",&a,&b); 
24.         p[find(a)]=p[find(b)];
25.         }
26. else
27.         {
28. scanf("%d %d",&a,&b);
29. if(p[find(a)]==p[find(b)]) puts("Yes");
30. else puts("No");
31.         }
32.     }
33. return 0;
34. }

连通块中点的数量

这题中的连通块我们可以看作集合中的元素,连接起来的连通块就是在一个集合当中,这题和上一题的区别就在于多了一个size大小,我们还需要维护一个size数组来记录当前集合中的元素个数,记录的方法就是当合并两个集合的时候,将A集合的size直接加到B集合中即可

AC代码

1. #include<iostream>
2. using namespace std;
3. const int N=100010;
4. int p[N],sz[N],n,m,a,b;
5. 
6. int find(int x)
7. {
8. if(p[x]!=x) p[x]=find(p[x]);
9. return p[x];
10. }
11. 
12. int main(void)
13. {
14. scanf("%d %d",&n,&m);
15. for(int i=1;i<=n;i++) 
16.     {
17.     p[i]=i;
18.     sz[i]=1;
19.     }
20. while(m--)
21.     {
22. char op[5];
23. scanf("%s",op);
24. if(op[0]=='C')
25.         {
26. scanf("%d %d",&a,&b);
27. if(find(a)==find(b)) continue;
28.             sz[find(a)]+=sz[find(b)];
29.             p[find(b)]=p[find(a)];
30.         }else if(op[1]=='1')
31.         {
32. scanf("%d %d",&a,&b);
33. if(find(a)==find(b))puts("Yes");
34. else puts("No");
35.         }else
36.         {
37. scanf("%d",&a);
38. printf("%d\n", sz[find(a)]);
39.         }
40.     }
41. return 0;
42. }


目录
相关文章
|
6月前
并查集。。
并查集。。
35 0
|
5月前
|
机器学习/深度学习 存储 算法
LeetCode 题目 95:从递归到动态规划实现 不同的二叉搜索树 II
LeetCode 题目 95:从递归到动态规划实现 不同的二叉搜索树 II
并查集及其应用
并查集及其应用
66 0
|
5月前
|
存储 算法 数据可视化
LeetCode 题目 96:从动态规划、递归到卡塔兰数实现不同的二叉搜索树
LeetCode 题目 96:从动态规划、递归到卡塔兰数实现不同的二叉搜索树
|
5月前
【洛谷 P1443】马的遍历 题解(广度优先搜索)
该问题是一个棋盘上的马的最短路径问题。给定一个$n\times m$的棋盘和起点$(x, y)$,需要计算马到达棋盘上每个位置的最短步数。输入包含$n, m, x, y$,输出是一个矩阵,表示各位置的步数或未可达的$-1$。使用广度优先搜索(BFS)策略,从起点开始遍历,直到访问完所有可达位置。代码中定义了太阳数组表示马的移动方向,并通过队列实现BFS。最后输出格式要求每个数字左对齐且域宽为5。
40 0
|
6月前
|
算法
算法题解-实现前缀树
算法题解-实现前缀树
|
6月前
|
机器学习/深度学习
并查集(UnionFind)总结
并查集(UnionFind)总结
64 0
|
算法
并查集模板题
并查集模板题
49 0
|
存储 算法 iOS开发
并查集详解及应用
并查集详解及应用
3851 0