●赘述题目

(题意就不赘述了)

●解法:

●我先想的一个比较暴力的方法(要TLE):

(ac自动机)先求出last数组(参见刘汝佳的解释:last[j]:表示j节点沿着失配指针往回走时,遇到的下一个单词节点(即单词在此结束)的编号),然后对输入的编号为y的字符串的每一个位置进行递归寻找是否能连上x字符串的结束节点。(给出失败代码片段图,就不解释了)

●正解:

(ac自动机)求出fail数组,然后以fail数组建树,如图

(看啊,红色的边和各点形成了另一棵树)

那么(看红树),若一个点在某个字符串结束节点的子树内,那么该字符串则出现在那个点所在的字符串里;如图中的a-b-c字符串和c字符串。

现在,我们若要求x字符串在y内出现了几次,就只需求以x的结束节点为根的子树内,有多少个节点是y字符串上的。

如何做呢?

将询问离线,y相同询问的弄在一起;

然后求出红树的dfs序(有点诡异,看代码);

我们再遍历一遍输入的字符串:

对于输入的‘a’-‘z’,把对应的dfs序中其出现的位置的值加1,用树状数组维护;

对于输入的‘B’,现在的字符所对应的dfs序中的位置的值减1;

对于遇到的c个‘P’,我们不难发现,现在的树状树状维护的便是第c个字符串的每一个字符在dfs序中的位置的值所加1后的结果。接着便可用区间查询求出y==c的询问的答案。

那么上代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<queue>
  4. #include<algorithm>
  5. #include<iostream>
  6. using namespace std;
  7. struct node{
  8. int x,y;
  9. } q[100005];
  10. struct edge{
  11. int to,next;
  12. }e[200005];
  13. int ch[100005][27];
  14. int val[100005],fail[100005],fa[100005],fini[100005],l[100005],r[100005],ans[100005];
  15. int head[100005],headq[100005],nxt[100005],lat[100005],c[150000];
  16. char x[100005];
  17. int cnt,pnt,ent=1,dnt,lx;
  18. int idx(char x) {return x-'a';}
  19. void modify(int u,int d) {for(int i=u;i<=dnt;i+=i&(-i)) c[i]+=d;}
  20. int query(int u) {int sum=0;for(int i=u;i;i-=i&(-i)) sum+=c[i]; return sum;}
  21. void add(int u,int v)
  22. {
  23. e[ent]=(edge){v,head[u]};head[u]=ent++;
  24. e[ent]=(edge){u,head[v]};head[v]=ent++;
  25. }
  26. void read_trie()
  27. {
  28. int u=0;
  29. for(int i=1;i<=lx;i++)
  30. {
  31. if(x[i]=='B') u=fa[u];
  32. else if(x[i]=='P') val[u]=++pnt,fini[pnt]=u;
  33. else
  34. {
  35. int c=idx(x[i]);
  36. if(!ch[u][c]) ch[u][c]=++cnt,fa[ch[u][c]]=u;
  37. u=ch[u][c];
  38. }
  39. }
  40. }
  41. void get_fail()
  42. {
  43. queue<int> q;
  44. for(int c=0;c<26;c++) {int u=ch[0][c]; if(u) q.push(u);}
  45. while(!q.empty())
  46. {
  47. int r=q.front(); q.pop();
  48. for(int c=0;c<26;c++)
  49. {
  50. if(!ch[r][c]) continue;
  51. int u=ch[r][c];
  52. q.push(u);
  53. int v=fail[r];
  54. while(v&&!ch[v][c]) v=fail[v];
  55. fail[u]=ch[v][c];
  56. }
  57. }
  58. }
  59. //----------------------------------------------------------------------
  60. void dfs_xu(int u,int fa)
  61. {
  62. l[u]=++dnt;
  63. for(int i=head[u];i;i=e[i].next) if(e[i].to!=fa) dfs_xu(e[i].to,u);
  64. r[u]=dnt;
  65. }
  66. void work()
  67. {
  68. int m; scanf("%d",&m);
  69. for(int i=1;i<=m;i++)
  70. {
  71. scanf("%d%d",&q[i].x,&q[i].y);
  72. nxt[i]=lat[q[i].y];
  73. lat[q[i].y]=i;
  74. }
  75. for(int i=1;i<=cnt;i++) add(i,fail[i]);
  76. dfs_xu(0,0);
  77. int p=0,id=0;
  78. for(int i=1;i<=lx;i++)
  79. {
  80. if (x[i]=='P')
  81. {
  82. id++;
  83. for (int j=lat[id];j;j=nxt[j])
  84. {
  85. int u=fini[q[j].x];
  86. ans[j]=query(r[u])-query(l[u]-1);
  87. }
  88. }
  89. else if (x[i]=='B') modify(l[p],-1),p=fa[p];
  90. else p=ch[p][idx(x[i])],modify(l[p],1);
  91. }
  92. for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
  93. }
  94. int main()
  95. {
  96. scanf("%s",x+1);
  97. lx=strlen(x+1);
  98. read_trie();
  99. get_fail();
  100. work();
  101. return 0;
  102. }

●BZOJ 2434: [Noi2011]阿狸的打字机的更多相关文章

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

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

  2. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

  3. bzoj 2434 [Noi2011]阿狸的打字机 AC自动机

    [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4001  Solved: 2198[Submit][Status][D ...

  4. 【刷题】BZOJ 2434 [Noi2011]阿狸的打字机

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  5. BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  6. bzoj 2434 [Noi2011]阿狸的打字机(fail树+离线处理+BIT)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2434 [题意] 按照一定规则生成n个字符串,回答若干个询问:(x,y),问第x个字符串 ...

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

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

  8. bzoj 2434 [Noi2011]阿狸的打字机——AC自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2434 dfs AC自动机,走过的点权值+1,回溯的时候权值-1:走到询问的 y 串的节点,看 ...

  9. bzoj 2434: [Noi2011]阿狸的打字机

    #include<cstdio> #include<iostream> #include<cstring> #define M 100008 using names ...

随机推荐

  1. C语言第二次博客作业——分支结构

    一.PTA实验作业 题目1:计算分段函数 1.实验代码 #include<stdio.h> #include<math.h> int main(void) { double x ...

  2. Vue.js学习

    <!DOCTYPE html> <html> <head> <title>xxx</title> </head> <bod ...

  3. exports

    暴露函数 var bar = require("./bar.js"); var msg = "你好"; var info = "呵呵"; f ...

  4. 20145237 《Java程序设计》第三周学习总结

    20145237 <Java程序设计>第3周学习总结 教材学习内容总结 第四章主要讲了Java基本类型中的类类型,如何定义类.构造函数.使用标准类.基本类型打包器.数组复制.字符串等内容查 ...

  5. ThreadLocal就是这么简单

    前言 今天要研究的是ThreadLocal,这个我在一年前学习JavaWeb基础的时候接触过一次,当时在baidu搜出来的第一篇博文ThreadLocal,在评论下很多开发者认为那博主理解错误,给出了 ...

  6. sql 几种循环方式

    1:游标方式 ALTER PROCEDURE [dbo].[testpro] as ) --日期拼接 ) --仪表编号 ) --数据采集表 ) --数据采集备份表 ) ) begin set @yea ...

  7. JAVA_SE基础——27.匿名对象

    黑马程序员入学blog... 匿名对象:没有引用类型变量指向的对象称作为匿名对象. 匿名对象要注意的事项:1. 我们一般不会给匿名对象赋予属性值,因为永远无法获取到.2. 两个匿名对象永远都不可能是同 ...

  8. Python struct模块

    有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体. struct模块中最重 ...

  9. python time、datetime、random、os、sys模块

    一.模块1.定义模块:用来从逻辑上组织Python代码(变量,函数,类,逻辑:实现一个功能),本质就是.py结尾的python文件(文件名:test.py,对应的模块名:test)包:用来从逻辑上组织 ...

  10. php代码一样,编码不同报错

    php代码一样,编码不同报错 两个php代码完全一样,但是就报错,比如说声明比如在very first,这种,可以把编码设置utf-8 无bom