题意

有一个打字机,支持三种操作:

  • 字符串末尾加一个小写字母
  • 字符串末尾减一个字符
  • 输出这个字符串

经过不超过\(n\)次操作后有\(m\)组询问:\((x,y)\),表示第\(x\)次输出第字符串在第\(y\)次输出第字符串里出现几次

\(n,m \leq 10^5\)

题解

每次加减字符就在trie树上走,输出的话记录一下在哪个结点

然后考虑询问\((x,y)\)暴力怎么做:\(x\)应该是\(y\)一个前缀的后缀,于是我们对于从根到\(y\)路径上每个结点(这相当于枚举\(y\)的后缀),从这个结点跳\(fail\),如果跳到\(x\)就\(ans++\),然后考虑下一个结点

实际上我们要求的就是根到\(y\)这条链上的结点中,在\(fail\)树中是\(x\)儿子的个数

我们可以按\(\text{trie}\)树的\(\text{dfs}\)序枚举\(y\),这样枚举所有的链和信息是\(O(n)\)的,每个点只会被加入一次和删除一次。然后考虑回答所有\((i,y)\)的询问,直接询问当前在\(x\)的\(fail\)树子树的结点个数。可以使用树状数组维护。具体说就是把询问按\(y\)在\(trie\)上的\(\text{dfs}\)序排序,然后每个点必须插入到它\(fail\)树\(\text{dfs}\)序的位置,查询就找到\(x\)的\(fail\)子树的\(\text{dfs}\)区间进行查询。

实现的话注意\(trie\)和\(fail\)不要搞混了,另外这题可以用主席树在线做

  1. #include <algorithm>
  2. #include <cstdio>
  3. #include <vector>
  4. using namespace std;
  5. const int N = 2e5 + 10;
  6. int ch[N][26], fa[N], fail[N];
  7. int dfn[N], dl[N], dr[N], dn[N];
  8. int pos = 1, id = 1, n, pt[N], ans[N];
  9. vector<int> fs[N];
  10. struct qs {
  11. int x, y, id;
  12. bool operator < (const qs &b) const {
  13. return dfn[y] < dfn[b.y];
  14. }
  15. } q[N];
  16. void work(char c) {
  17. if(c == 'B') pos = fa[pos];
  18. else if(c == 'P') pt[++ pt[0]] = pos;
  19. else {
  20. int &v = ch[pos][c - 'a'];
  21. if(!v) {
  22. v = ++ id;
  23. fa[v] = pos;
  24. }
  25. pos = v;
  26. }
  27. }
  28. void dfs(int u) { //on trie
  29. dfn[u] = ++ dfn[0]; dn[dfn[0]] = u;
  30. for(int i = 0; i < 26; i ++)
  31. if(ch[u][i]) dfs(ch[u][i]);
  32. }
  33. void buildac() {
  34. static int q[N], l, r, v;
  35. for(int i = 0; i < 26; i ++) if(v = ch[1][i]) {
  36. q[r ++] = v; fail[v] = 1;
  37. } else ch[1][i] = 1;
  38. while(l < r) {
  39. int u = q[l ++];
  40. for(int i = 0; i < 26; i ++) if(v = ch[u][i]) {
  41. q[r ++] = v; fail[v] = ch[fail[u]][i];
  42. } else ch[u][i] = ch[fail[u]][i];
  43. }
  44. for(int i = 2; i <= id; i ++)
  45. fs[fail[i]].push_back(i);
  46. }
  47. void dfs2(int u) { //on fail tree
  48. dl[u] = ++ dl[0];
  49. for(int i = 0; i < fs[u].size(); i ++) dfs2(fs[u][i]);
  50. dr[u] = dl[0];
  51. }
  52. int bit[N];
  53. void add(int x, int y) {
  54. for(; x <= id; x += x & (-x)) bit[x] += y;
  55. }
  56. int qry(int x) {
  57. int ans = 0;
  58. for(; x >= 1; x &= x - 1) ans += bit[x];
  59. return ans;
  60. }
  61. int main() {
  62. static char s[N]; scanf("%s", s);
  63. for(char *c = s; *c; c ++) work(*c);
  64. dfs(1); buildac(); dfs2(1);
  65. scanf("%d", &n);
  66. for(int i = 1; i <= n; i ++) {
  67. scanf("%d%d", &q[i].x, &q[i].y);
  68. q[i].x = pt[q[i].x];
  69. q[i].y = pt[q[i].y]; //id -> node
  70. q[i].id = i;
  71. }
  72. sort(q + 1, q + n + 1);
  73. for(int i = 1, j = 1; i <= id; i ++) {
  74. int u = dn[i];
  75. if(i > 1) {
  76. int la = dn[i - 1];
  77. while(la != fa[u]) {
  78. add(dl[la], -1);
  79. la = fa[la];
  80. }
  81. }
  82. add(dl[u], 1);
  83. for(; j <= n && dfn[q[j].y] == i; j ++) {
  84. ans[q[j].id] = qry(dr[q[j].x]) - qry(dl[q[j].x] - 1);
  85. }
  86. }
  87. for(int i = 1; i <= n; i ++)
  88. printf("%d\n", ans[i]);
  89. return 0;
  90. }

「BZOJ 2434」「NOI 2011」阿狸的打字机「AC自动机」的更多相关文章

  1. 【BZOJ 2434】【NOI 2011】阿狸的打字机 fail树

    完全不会啊,看题解还看了好久,我是蒟蒻$QAQ$ $zyf$的题解挺好的:http://blog.csdn.net/clove_unique/article/details/51059425 $fai ...

  2. BZOJ 2434 [Noi2011]阿狸的打字机(AC自动机)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2434 [题目大意] 给出一个打印的过程,'a'-'z'表示输入字母,P表示打印该字符串 ...

  3. NOI 2011 阿狸的打字机(AC自动机+主席树)

    题意 https://loj.ac/problem/2444 思路 ​多串匹配,考虑 \(\text{AC}\) 自动机.模拟打字的过程,先建出一棵 \(\text{Trie}\) 树,把它变成自动机 ...

  4. 【NOI 2011】阿狸的打字机

    Problem Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有 \(28\) 个按键,分别印有 \(26\) 个小写英文字母和 B . P 两个字母. ...

  5. NOI 2011 【阿狸的打字机】

    之前讲了[AC自动姬],今天我终于把这题给刚下来了...嗯,来给大家讲一讲. 题目描述: 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工 ...

  6. 「AC自动机」学习笔记

    AC自动机(Aho-Corasick Automaton),虽然不能够帮你自动AC,但是真的还是非常神奇的一个数据结构.AC自动机用来处理多模式串匹配问题,可以看做是KMP(单模式串匹配问题)的升级版 ...

  7. 「BZOJ 4228」Tibbar的后花园

    「BZOJ 4228」Tibbar的后花园 Please contact lydsy2012@163.com! 警告 解题思路 可以证明最终的图中所有点的度数都 \(< 3\) ,且不存在环长是 ...

  8. 「BZOJ 3645」小朋友与二叉树

    「BZOJ 3645」小朋友与二叉树 解题思路 令 \(G(x)\) 为关于可选大小集合的生成函数,即 \[ G(x)=\sum[i\in c ] x^i \] 令 \(F(x)\) 第 \(n\) ...

  9. 「BZOJ 4502」串

    「BZOJ 4502」串 题目描述 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合 \(S\),然后它们定义一个字符串为"好"的,当且仅当它可以被分成非空的两段,其中每一段 ...

随机推荐

  1. SQL Server2005中文版x64安装29506错误解决办法

    在使用SQL Server 2005简体中版安装时,使用X86(32位操作系统下)安装没有出现任何问题.可是在X64(64位操作系统下)安装过程没有出现问题,可是安装完成后却没有Microsoft S ...

  2. Nginx反向代理图片总结

    配置需求: 内网192.168.80.205的机器上部署了一个Web项目,下文称web,   url为http://192.168.80.205:8082.   并且使用nginx访问图片,url格式 ...

  3. oracle 12c使用问题总结

    1.无法登录 安装完毕只能使用system和sys用户,用安装时配置的密码登录:不能使用默认密码 2.远程无法访问 1)检测服务器配置 lsnrctl status 看到(DESCRIPTION=(A ...

  4. 【phonegap】下载文件

    <!-- 打包的时候phonegap自己会添加这个文件--> <script type="text/javascript" charset="utf-8 ...

  5. PHP字符串的处理(三)-字符串的输出

    1.echo() echo()实际不是一个函数,是一个语言结构,不需要使用括号 <?php $str = "test"; echo $str."<br> ...

  6. [原创]20行ruby代码实现依赖注入框架

    我需要依赖注入 业余时间开发的娱乐项目 (为了练习使用ruby语言) 遵循SRP原则,业务逻辑拆分由各个service类型提供,假设存在如下几个类型 GameService 封装主要游戏业务逻辑 Us ...

  7. Burpsuite模块—-Intruder模块详解

    一.简介 Burp Intruder是一个强大的工具,用于自动对Web应用程序自定义的攻击,Burp Intruder 是高度可配置的,并被用来在广范围内进行自动化攻击.你可以使用 Burp Intr ...

  8. 自定义对话框<转>

    效果如下: <ignore_js_op> QQ截图20130221234404.png (51.02 KB, 下载次数: 126) 下载附件  保存到相册 2013-2-21 23:44 ...

  9. 前端性能分析:分析百度和sogou

    先用httpwatch录制这两个网站:www.baidu.com  www.sogou.com 由上图可以看到: 百度用时0.278s 发送7831B 接收36620B 13个请求 搜狗       ...

  10. 小程序为什么脚本内不能使用window等对象

    小程序(应用号)内不能使用window等对象. 页面的脚本逻辑在是在JsCore中运行,JsCore是一个没有窗口对象的环境,所以不能再脚本中使用window,也无法在脚本中操作组件.