题意:有N个串,给出的形式是拼接给出,对于第i行:  (1,c)表示字符串i是单个字母c; (2,p,c)表示字符串i=在字符串p后面接上一个字母c。

然后给出M个提问,形式是(i,string)。问string在字符串i中出现了多少次。

思路:这类题显然是在AC自动机上乱搞。  对于询问的串建立AC自动机,BFS建立fail树;那么一个询问其实就是第i个串的位置到根的这些节点,有多少个在string节点的子树里。      即给一条链染色,然后询问一个点是子树里多少点被染色了。 为了不重不漏,  我们用回溯就可以处理了。 然后用树状数组维护DFS序下的前缀和。

具体的,对于N个串在AC自动机上跑,每跑一步对应N个字符串之一。 每跑到一个节点,就加加。 跑完子树后就减减,保证了加的部分是一条链。

  1. #include<bits/stdc++.h>
  2. #define pii pair<int,int>
  3. #define pb push_back
  4. #define rep(i,a,b) for(int i=a;i<=b;i++)
  5. using namespace std;
  6. const int maxn=;
  7. vector<pii>G[maxn],Q[maxn];
  8. vector<int>F[maxn];
  9. int ch[maxn][],fail[maxn],ans[maxn],tot;
  10. int in[maxn],out[maxn],times; //dfn
  11. char s[maxn]; int sum[maxn];
  12. void add(int x,int val){ while(x<=times) sum[x]+=val,x+=(-x)&x;}
  13. int query(int x){ int res=; while(x){ res+=sum[x]; x-=(-x)&x; } return res;}
  14. int add()
  15. {
  16. int now=,L=strlen(s);
  17. rep(i,,L-) {
  18. if(!ch[now][s[i]-'a']) ch[now][s[i]-'a']=++tot;
  19. now=ch[now][s[i]-'a'];
  20. } return now;
  21. }
  22. void build()
  23. {
  24. queue<int>q;
  25. rep(i,,) if(ch[][i]) q.push(ch[][i]);
  26. while(!q.empty()){
  27. int u=q.front(); q.pop();
  28. rep(i,,) {
  29. if(ch[u][i]){
  30. fail[ch[u][i]]=ch[fail[u]][i];
  31. q.push(ch[u][i]);
  32. }
  33. else ch[u][i]=ch[fail[u]][i];
  34. }
  35. }
  36. rep(i,,tot) F[fail[i]].push_back(i);
  37. }
  38. void dfs(int u)
  39. {
  40. in[u]=++times;
  41. for(int i=;i<F[u].size();i++) dfs(F[u][i]);
  42. out[u]=times;
  43. }
  44. void dfs(int u,int now) //u是位置,now是id
  45. {
  46. add(in[u],);
  47. for(int i=;i<Q[now].size();i++){
  48. pii t=Q[now][i];
  49. ans[t.second]=query(out[t.first])-query(in[t.first]-);
  50. }
  51. for(int i=;i<G[now].size();i++){
  52. pii t=G[now][i];
  53. dfs(ch[u][t.first],t.second);
  54. }
  55. add(in[u],-);
  56. }
  57. int main()
  58. {
  59. int N,M,opt,p;
  60. scanf("%d",&N);
  61. rep(i,,N) {
  62. scanf("%d",&opt);
  63. if(opt==) p=;
  64. else scanf("%d",&p);
  65. scanf("%s",s);
  66. G[p].pb(pii(s[]-'a',i));
  67. }
  68. scanf("%d",&M);
  69. rep(i,,M) {
  70. scanf("%d%s",&p,s);
  71. Q[p].pb(pii(add(),i));
  72. }
  73. build();
  74. dfs();
  75. dfs(,);
  76. rep(i,,M) printf("%d\n",ans[i]);
  77. return ;
  78. }

CodeForces - 1207G :Indie Album(AC自动机 fail树上DFS)的更多相关文章

  1. AC自动机fail树上dfs序建线段树+动态memset清空

    题意:http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路:https://blog.csdn.net/u013306830/article/detail ...

  2. CF G. Indie Album AC自动机+fail树+线段树

    这个套路挺有意思的. 把 $trie$ 和 $fail$ 树都建出来,然后一起跑一跑就好了~ #include <queue> #include <cstdio> #inclu ...

  3. ac自动机fail树上按询问建立上跳指针——cf963D

    解法看着吓人,其实就是为了优化ac自动机上暴力跳fail指针.. 另外这题对于复杂度的分析很有学习价值 /* 给定一个母串s,再给定n个询问(k,m) 对于每个询问,求出长度最小的t,使t是s的子串, ...

  4. 洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)

    要点 这是一道蔡队题,看我标题行事 任意询问y串上有多少个x串,暴力找每个节点是不是结尾肯定是炸的,考虑本质:如果某节点是x的结尾,根据ac自动机的性质,x一定是此(子)串后缀.又有每个Trie节点的 ...

  5. BZOJ 2905: 背单词 AC自动机+fail树+dfs序+线段树

    Description 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使得其中的每个单词是后一个单词的子串,最大化子序列中W的和. Input 第一行一个整数TEST,表示数据组 ...

  6. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

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

  7. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

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

  8. 【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组

    E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  9. 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 508  Solved: 158[Submit][Sta ...

随机推荐

  1. centos7 安装hadoop2.7.6(分布式)

    本文只做简单介绍,具体步骤操作请参考centos6.5 安装hadoop1.2.1亲测版 本篇只简单介绍安装步骤 1.安装目录 /usr/local/hadoop (HADOOP_HOME) 2,创建 ...

  2. c++ builder调用sql server的存储过程进行数据的下载和上传

    小小的几行代码,在这里搞了一天.好好的一个周六过的无比的难受.代码很简单,但是主要原因是因为在用合作商的软件上传数据的时候有些框框没有勾选. come on....... 1.用两个控件ADOConn ...

  3. Android集成C程序访问驱动设备节点

    1.前言 Android系统中,应用程序一般是使用Java语言进行开发的,但是通过C语言也可以进行Android中的可执行程序开发,接下来,将简单介绍在Android系统中如何通过C程序来访问内核中s ...

  4. [转帖]10分钟看懂Docker和K8S

    10分钟看懂Docker和K8S https://zhuanlan.zhihu.com/p/53260098 2010年,几个搞IT的年轻人,在美国旧金山成立了一家名叫“dotCloud”的公司. 这 ...

  5. Docker在Windows上的初体验

    作为Docker的初学者,我有几个疑问,找到了答案,并实践了一下,希望对和我一样的初学者有帮助: 1.Docker是什么? 大家对虚拟机应该比较熟悉,虚拟机和docker都是为了实现隔离. 虚拟机隔离 ...

  6. Mysql 表分区分类

    针对Mysql数据库,表分区类型简析. [1]表分区类型 (1)Range分区:按范围分区.按列值的范围区间进行分区存储:比如:id小于10存储在一个分区:id大于10小于20存储在另外一个分区: ( ...

  7. BZOJ3926 ZJOI2015诸神眷顾的幻想乡(广义后缀自动机)

    对多串建立SAM的一种方法是建trie再对trie建SAM.构造方式分为在线(也即不建trie而是依次插入每个串,或在trie上dfs)和离线(也即建好trie再bfs).其中离线构造与单串的构造方式 ...

  8. SQL 2008R2问题:用户、组或角色'XXX'在当前数据库中已存在?

    为一个数据库添加一个用户或者映射数据库时,提示以下错误信息: 用户.组或角色 '*****' 在当前数据库中已存在. (Microsoft SQLServer, 错误 : 15023) 问题原因:在还 ...

  9. 运维利器1-supervisor

    supervisor用来管理进程服务很方便 优点: 1.重启方便,无抖动感 2.可以分组管理进程 3.加入系统自动启动后,可以开机自启,程序异常退出能自动启动 操作: 1.在python沙箱环境下操作 ...

  10. gcc 编译过程

    gcc 编译过程从 hello.c 到 hello(或 a.out)文件, 必须历经 hello.i. hello.s. hello.o,最后才得到 hello(或a.out)文件,分别对应着预处理. ...