CODEVS 2542单词__fail树
2542 单词
2013年省队选拔赛天津市队选拔赛
小张最近在忙毕业,所以一直在读论文。一篇论文是由许多单词组成的。
但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次。
第一行一个整数N,表示有N个单词,接下来N行,每行一个单词,每个单词都由小写字母组成(N<=200)
输出N个整数,第i行的数表示第i个单词在文章中出现了多少次。
3
a
aa
aaa
6
3
1
30%的数据 单词总长度不超过10^3
100%的数据 单词总长度不超过10^6
————————————————————————————————————————————————————————————————————————————————
一看是AC自动机是没有问题的,但是建完AC自动机后该如何做呢?
当然可以直接用AC自动机的fail指针向前跳,但是这样要枚举单词内的每个位置,严重超时。
这里要用到一个很有用的工具——fail树。
当AC自动机建完以后,我们发现每一个节点都只有一个失败指针(根节点的可以忽略),且沿着失败指针最终能走到根节点。
这样我们将失败指针反向就可以变成一棵树。
这棵树的有些重要的性质:
1、以x节点为根的子树中每个节点代表的字符串都以x点所代表的字符串为后缀。
2、节点x代表的字符串的最大后缀为父节点代表的字符串。
这样我们在插入字符串是把经过的每个节点的val值都加1,就相当于统计的对应前缀出现的次数。
然后通过dfs将val变为val加它所有子树的val和。也就是以(s)为前缀的字符串个数+以(*+s)为前缀的字符串的个数+以(**+s)为前缀的个数+。。。。。
这样s出现的次数就是s串尾对应的val值。
比较难想,但是fail树真的很有用。
————————————————————————————————————————————————————————————————————————————————
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn=1e6+3;
4 const int maxs=26;
5 struct edge{
6 int u,v,next;
7 }e[maxn];
8 int head[maxn],js=0;
9 void addage(int u,int v)
10 {
11 e[++js].u=u;e[js].v=v;
12 e[js].next=head[u];head[u]=js;
13 }
14 struct AC{
15 int ch[maxn][maxs];
16 int val[maxn],f[maxn];
17 int sz;
18 AC(){
19 memset(ch[0],0,sizeof(ch[0]));
20 val[0]=0;
21 sz=1;
22 }
23 int idx(char c){
24 return c-'a';
25 }
26 int insert(char *s){
27 int n=strlen(s),cur=0;
28 for(int i=0,c;i<n;i++){
29 c=idx(s[i]);
30 if(!ch[cur][c]){
31 memset(ch[sz],0,sizeof(sz));
32 val[sz]=0;
33 ch[cur][c]=sz++;
34 }
35 cur=ch[cur][c];
36 val[cur]++;
37 }
38 return cur;
39 }
40 void getfail(){
41 queue<int>q;
42 f[0]=0;
43 for(int c=0;c<maxs;c++){
44 int v=ch[0][c];
45 if(v){
46 f[v]=0;
47 q.push(v);
48 addage(0,v);
49 }
50 }
51 while(!q.empty()){
52 int u=q.front();q.pop();
53 for(int c=0;c<maxs;++c){
54 int v=ch[u][c];
55 if(v){
56 q.push(v);
57 int r=f[u];
58 while(r && !ch[r][c])r=f[r];
59 f[v]=ch[r][c];
60 addage(f[v],v);
61 }
62 }
63 }
64 }
65 }ac;
66 int n;
67 int wz[201];
68 char s[maxn];
69 void dfs(int u,int f)
70 {
71 for(int i=head[u];i;i=e[i].next){
72 int u=e[i].u,v=e[i].v;
73 if(v==f)continue;
74 dfs(v,u);
75 ac.val[u]+=ac.val[v];
76 }
77 }
78 int main()
79 {
80 scanf("%d",&n);
81 for(int i=0;i<n;++i){
82 scanf("%s",s);
83 wz[i]=ac.insert(s);
84 }
85 ac.getfail();
86 dfs(0,-1);
87 for(int i=0;i<n;i++)
88 printf("%d\n",ac.val[wz[i]]);
89 return 0;
90 }
CODEVS 2542单词__fail树的更多相关文章
- codevs 1729 单词查找树
二次联通门 : codevs 1729 单词查找树 /* codevs 1729 单词查找树 Trie树 统计节点个数 建一棵Trie树 插入单词时每新开一个节点就计数器加1 */ #include ...
- 【NOI2000】 单词查找树
问题描述 在进行文法分析的时候,通常需要检测一个单词是否在我们的单词列表里.为了提高查找和定位的速度,通常都画出与单词列表所对应的单词查找树,其特点如下: 根结点不包含字母,除根结点外每一个结点都仅包 ...
- K:单词查找树(Trie)
单词查找树,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串.Trie可以看作是一个确定有限状态自动机(DFA).与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中 ...
- COGS 293.[NOI2000] 单词查找树
★ 输入文件:trie.in 输出文件:trie.out 简单对比 时间限制:1 s 内存限制:128 MB 在进行文法分析的时候,通常需要检测一个单词是否在我们的单词列表里.为了提高 ...
- 1729 单词查找树 2000年NOI全国竞赛
1729 单词查找树 2000年NOI全国竞赛 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 在进行文法分析的 ...
- Trie树,又称单词查找树、字典
在百度或淘宝搜索时,每输入字符都会出现搜索建议,比如输入“北京”,搜索框下面会以北京为前缀,展示“北京爱情故事”.“北京公交”.“北京医院”等等搜索词.实现这类技术后台所采用的数据结构是什么?[中国某 ...
- [NOI2000] 单词查找树
★★ 输入文件:trie.in 输出文件:trie.out 简单对比 时间限制:1 s 内存限制:128 MB 在进行文法分析的时候,通常需要检测一个单词是否在我们的单词列表里.为了提 ...
- 293. [NOI2000] 单词查找树——COGS
293. [NOI2000] 单词查找树 ★★ 输入文件:trie.in 输出文件:trie.out 简单对比时间限制:1 s 内存限制:128 MB 在进行文法分析的时候,通常需要检 ...
- cogs 293. [NOI 2000] 单词查找树 Trie树字典树
293. [NOI 2000] 单词查找树 ★★☆ 输入文件:trie.in 输出文件:trie.out 简单对比时间限制:1 s 内存限制:128 MB 在进行文法分析的时候,通常需 ...
随机推荐
- [LeetCode]86. Partition List分离链表
/* 这个题是medium的意思应该是用双指针的方法做,如果使用下边的新建链表的方法,就是easy的题目了 双指针会用到很多链表的相连操作 */ public ListNode partition(L ...
- 嵌入式Linux-LCD显示多行文字
显示文字这里我用了freetype库. 以左上角显示两行文字: #include <sys/types.h> #include <sys/stat.h> #include &l ...
- zookeeper选举算法
一.ZAB协议三阶段 – 发现(Discovery),即选举Leader过程– 同步(Synchronization),选举出新的Leader后,Follwer或者Observer从Leader同步最 ...
- pixi.js 图像资源(svg)转纹理
当Pixi使用WebGL去调用GPU渲染图像时,需要先将图像转化为GPU可以处理的版本.而能够被GPU处理的图像就叫做纹理,在pixi中使用纹理缓存来存储和引用所有纹理.通过将纹理分配给精灵,再将精灵 ...
- Turtlebot3新手教程-应用-跟随
本文针对如何利用Turtlebot3可实现的各种应用进行讲解 具体步骤如下: [Remote PC]安装应用包 cd ~/catkin_ws/src git clone https://github. ...
- 第5章节 BJROBOT SLAM 构建地图
第五章节 BJROBOT SLAM 构建地图 建地图前说明:请确保你的小车已经校正好 IMU.角速度.线速度,虚拟机配置好 ROS 网络的前提进行,否则会造成构建地图无边界.虚拟机端无法正常收到小 ...
- 效率工具 | 快速创建虚拟机,Vagrant真香!
Vagrant 是一个基于Ruby的工具,主要用于创建和部署虚拟化开发环境.它以来于Oracle的开源VirtualBox虚拟化系统,通过使用 Chef创建自动化虚拟环境. Vagrant 主要的功能 ...
- MyBatis中id回填的两种方式
在一种场景下需要刚刚插入数据的ID,如果数据少可以先看数据库,记下ID,但数据很多,假设一万个用户并发,每个用户都插入自己的ID,就很难记下来. 下面给定一个场景: 1 User user = new ...
- 通过实例学习 PyTorch
通过范例学习 PyTorch 本博文通过几个独立的例子介绍了 PyTorch 的基础概念. 其核心,PyTorch 提供了两个主要的特征: 一个 n-维张量(n-dimensional Tensor) ...
- servlet+jsp完成简单登录
将用户在注册界面中的数据填充到数据库相对应的表格中.当用户再次登录时,从数据库中拿到相应的数据查询并与页面的数据做对比,判断是否登陆成功. 需要在HTML文件中将form表单上的action属性值设置 ...