P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)

传送门

形式上,AC 自动机基于由若干模式串构成的 Trie 树,并在此之上增加了一些 fail 边;本质上,AC 自动机是一个关于若干模式串的DFA(确定有限状态自动机),接受且仅接受以某一个模式串作为后缀的字符串。 并且,与一般自动机不同的,AC 自动机还有关于某个模式串的接受状态,也就是与某个模式串匹配(以某个模式串为后缀)的那些状态,即某个模式串在 Trie树上的终止节点在 fail 树上的整个子树。

暴力跳 fail 边,会被类似于 aaaaa……aaaaa 这样的串卡掉。

正确的做法是建出 fail 树,记录自动机上的每个状态被匹配了几次,最后求出每个模式串在 Trie 上的终止节点在 fail 树上的子树总匹配次数就可以了,我们dfs建立好的fail树,从当前结点的失配指针指向的结点向该结点连边建fail树,这样我们dfs该树的时候可以保证每一条边(u,v)(u,v)(u,v),u到根节点之间的串等于v到根节点之间的串,那么该串的出现次数就是所有的边(u,v)(u,v)(u,v),的size之和。不会加重, 因为fail树是由fail指针边构成的,然而所有的点只会建立一个fail指针。例如有三个相同的模式串,只会有两个fail指针。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>using namespace std;const int N = 200010, S = 2000010;queue<int>q;
struct trie{int fail;int vis[26];int ed;
}ac[N];int match[N];
int n;
int tot, sizes[N];
int head[N], nex[N], ver[N], cnt, num;void add(int x, int y){ver[cnt] = y;nex[cnt] = head[x];head[x] = cnt ++ ;
}void insert(int x, char s[]){int len = strlen(s);int p = 0;//根从0开始for(int i = 0; i < len; ++ i){int ch = s[i] - 'a';if(!ac[p].vis[ch])ac[p].vis[ch] = ++ tot;p = ac[p].vis[ch];}ac[p].ed ++ ;match[x] = p;//记录每个模式串在 Trie 树上的终止节点
}void get_fail(){for(int i = 0;i < 26; ++ i){if(ac[0].vis[i]){ac[ac[0].vis[i]].fail = 0;q.push(ac[0].vis[i]);}}while(q.size()){int p = q.front();q.pop();for(int i = 0;i < 26; ++ i){if(ac[p].vis[i]){ac[ac[p].vis[i]].fail = ac[ac[p].fail].vis[i];q.push(ac[p].vis[i]);}else ac[p].vis[i] = ac[ac[p].fail].vis[i];}}
}void dfs(int x){for(int i = head[x]; ~i; i = nex[i]){int y = ver[i];dfs(y);sizes[x] += sizes[y];}
}int ac_query(char s[]){int p = 0, ans = 0;int len = strlen(s);for(int i = 0;i < len;++i){//!计算有多少个单词在文本中出现p = ac[p].vis[s[i]-'a'];//往下一层走for(int k = p;k&&ac[k].ed!=-1;k = ac[k].fail){ans += ac[k].ed;ac[k].ed = -1;}}p = 0;for(int i = 0; i < len; ++ i){p = ac[p].vis[s[i] - 'a'];sizes[p] ++ ;//!记录匹配次数}for(int i = 1; i <= tot; ++ i)//!建fail树add(ac[i].fail, i);dfs(0);//!统计子树和for(int i = 1;i <= n; ++ i)printf("%d\n", sizes[match[i]]);return ans;
}char s[S];int main(){scanf("%d", &n);memset(head, -1, sizeof head);for(int i = 1;i <= n; ++ i){scanf("%s", s);insert(i, s);}//cout << "ok" << num ++  << endl;get_fail();//cout << "ok" << num ++  << endl;scanf("%s", s);//cout << "ok" << num ++  << endl;int res = ac_query(s);//cout << res << endl;return 0;
}

P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)相关推荐

  1. bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 3521  Solved: 1913 [Submit][S ...

  2. CodeForces - 1437G Death DBMS(AC自动机fail树上树链剖分建线段树/暴跳fail)

    题目链接:点击查看 题目大意:给出 n 个模式串,每个模式串初始时的权值为 0,然后有 m 次操作: 1 i x:将第 i 个模式串的权值修改为 x 2 s:给出一个字符串 s,询问字符串 s 作为主 ...

  3. 洛谷P5357 - 【模板】AC自动机(二次加强版)(AC自动机+fail树)

    题目链接:点击查看 题目大意:给出n个模式串,问在主串中分别出现了多少次 题目分析:如果像以往那样,在匹配的时候fail指针乱跳的话,那么是错误的AC自动机使用方法,时间复杂度也大大上升,接近于暴力的 ...

  4. 【数据结构】自动机全家桶(AC、回文、后缀自动机)

    自动机全家桶 前言 一.AC自动机 1.优秀博客链接 2.问题模板 3.使用 4.本质 5.运用 6.代码模板 二.回文自动机(回文树) 1.优秀博客链接 2.问题模板 3.使用 4.本质 5.运用 ...

  5. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 2545  Solved: 1419 [Submit][S ...

  6. AC自动机 - 多模式串的匹配 --- HDU 3695 Computer Virus on Planet Pandora

    Problem's Link Mean: 有n个模式串和一篇文章,统计有多少模式串在文章中出现(正反统计两次). analyse: 好久没写AC自动机了,回顾一下AC自动机的知识. 本题在构造文章的时 ...

  7. HDU 4787 在线AC自动机 分块(模式串和母串交叉给出,多次求getFail)

    题意: 给定T个测试数据 n个操作 + 插入单词 ? 询问母串中有多少个子串 在上面出现过 ( 子串被加密,即←移动L位 (L为上次询问的答案) ) 分块思路: 因为模式串和母串交叉给出,正常来说应该 ...

  8. Xamarin XAML语言教程模板视图TemplatedView(二)

    Xamarin XAML语言教程模板视图TemplatedView(二) (2)打开MainPage.xaml文件,编写代码,将构建的控件模板应用于中TemplatedView.代码如下: <? ...

  9. GIS实战应用案例100篇(二)-元胞自动机模拟城市扩张过程

    前言 CA模型:CA(Cellular Automat)即元胞自动机模型,元胞自动机是一种具有时空计算特征的模型框架,从局部到整体的建模思想被广泛的应用于空间上离散.时间上也离散的复杂性系统模拟.标准 ...

最新文章

  1. SEO那些事:一句代码一键分享网站
  2. JavaScript之match()方法讲解
  3. 请简单解释一下ARP协议和ARP攻击
  4. Convert(varchar(8),Getdate(),108) 什么意思
  5. ISE报错问题集锦(转载)
  6. ansys命令流_ANSYS命令流建模3之划分单元+施加弹簧
  7. 关于myeclipse输入法编程繁体的修正
  8. 在PHP中对象真的是按引用传递的吗
  9. python自助电影售票机_手把手教你用python抢票回家过年(代码简单)
  10. samba配置过程(附网络凭据的解决方法)
  11. c语言 自定义strcmp
  12. vim 模式下的几个快捷用法
  13. Oracle OAF 学习小结(1)- 个性化详解
  14. 叶俊|从人类基因本能谈到赞美的力量|麻辣总裁幽默SHOW嗨翻全场
  15. 给大家分享一篇 用Python抓取漫画并制作mobi格式电子书
  16. 苹果签名是什么?苹果签名的作用是什么?
  17. python基础知识大一总结与反思_反思总结及规划 其一
  18. 简单整系数滤波器去除心电信号的基线漂移
  19. 教师资格证计算机科目有哪些内容,初中教师资格证考试科目及内容有哪些?
  20. HTML基础的回顾复习(基本标签,简单的一个登陆验证)

热门文章

  1. 2012年至今,细数深度学习领域这些年取得的经典成果
  2. OpenCV 新版 4.5.1 发布!
  3. 用30行代码做一个微信智障机器人
  4. 推特雪花算法 java实现
  5. 怎么将两个list集合按照条件合成一个list
  6. 安装Hadoop系列 — 导入Hadoop源码项目
  7. 命令行下编译Wordcount
  8. 用C语言实现素数筛法获取一亿(100000000)以内的全部素数
  9. [Unity3D]总结使用Unity 3D优化游戏运行性能的经验
  10. javascript密码强度验证!