题目描述

Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。
接下来会发生q个操作,操作有两种形式:
“1 P”,Bob往自己的集合里添加了一个字符串P。
“2 x”,Alice询问Bob,集合T中有多少个字符串包含串S_x。(我们称串A包含串B,当且仅当B是A的子串)
Bob遇到了困难,需要你的帮助。

输入

第1行,一个数n;
接下来n行,每行一个字符串表示S_i;
下一行,一个数q;
接下来q行,每行一个操作,格式见题目描述。

输出

对于每一个Alice的询问,帮Bob输出答案。

样例输入

3
a
bc
abc
5
1 abca
2 1
1 bca
2 2
2 3

样例输出

1
2
1


题解

AC自动机+树链的并+DFS序+树状数组

P的子串体现为前缀的后缀,某个前缀的所有后缀在AC自动机上体现为:Trie树上该前缀对应节点的fail树到根节点的链上节点。

因此对所有S串建立AC自动机,求出fail树,那么添加一个P串,它所包含的S串的范围就是P在Trie树上每个位置(P的每个前缀)fail树上到根节点所覆盖的所有节点,即把树链的并+1。

把所有位置按照DFS序排序,每个点到根节点路径上+1,每相邻两点LCA到根节点路径上-1。查询就是查单点权值。需要支持:到根节点的路径加、单点求值,差分后变为单点加、子树求值,使用DFS将子树转化为区间,再用树状数组维护区间和即可。

时间复杂度 $O(n\log n)$ 。

  1. #include <queue>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #define N 100010
  5. #define M 2000010
  6. using namespace std;
  7. queue<int> q;
  8. int c[M][26] , fail[M] , tot = 1 , pos[N] , head[M] , to[M] , next[M] , cnt , fa[M][20] , deep[M] , log[M] , vp[M] , lp[M] , tp , f[M] , val[M] , tv;
  9. char str[M];
  10. void build()
  11. {
  12. int x , i;
  13. for(i = 0 ; i < 26 ; i ++ ) c[0][i] = 1;
  14. q.push(1);
  15. while(!q.empty())
  16. {
  17. x = q.front() , q.pop();
  18. for(i = 0 ; i < 26 ; i ++ )
  19. {
  20. if(c[x][i]) fail[c[x][i]] = c[fail[x]][i] , q.push(c[x][i]);
  21. else c[x][i] = c[fail[x]][i];
  22. }
  23. }
  24. }
  25. inline void add(int x , int y)
  26. {
  27. to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
  28. }
  29. void dfs(int x)
  30. {
  31. int i;
  32. vp[x] = ++tp;
  33. for(i = 1 ; i <= log[deep[x]] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
  34. for(i = head[x] ; i ; i = next[i]) fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]);
  35. lp[x] = tp;
  36. }
  37. inline int lca(int x , int y)
  38. {
  39. int i;
  40. if(deep[x] < deep[y]) swap(x , y);
  41. for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
  42. if(deep[x] - deep[y] >= (1 << i))
  43. x = fa[x][i];
  44. if(x == y) return x;
  45. for(i = log[deep[x]] ; ~i ; i -- )
  46. if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i])
  47. x = fa[x][i] , y = fa[y][i];
  48. return fa[x][0];
  49. }
  50. inline void fix(int x , int a)
  51. {
  52. int i;
  53. for(i = x ; i <= tp ; i += i & -i) f[i] += a;
  54. }
  55. inline int query(int x)
  56. {
  57. int i , ans = 0;
  58. for(i = x ; i ; i -= i & -i) ans += f[i];
  59. return ans;
  60. }
  61. bool cmp(int a , int b)
  62. {
  63. return vp[a] < vp[b];
  64. }
  65. int main()
  66. {
  67. int n , m , i , j , t , opt , x;
  68. scanf("%d" , &n);
  69. for(i = 1 ; i <= n ; i ++ )
  70. {
  71. scanf("%s" , str) , t = 1;
  72. for(j = 0 ; str[j] ; j ++ )
  73. {
  74. if(!c[t][str[j] - 'a']) c[t][str[j] - 'a'] = ++tot;
  75. t = c[t][str[j] - 'a'];
  76. }
  77. pos[i] = t;
  78. }
  79. build();
  80. for(i = 2 ; i <= tot ; i ++ ) add(fail[i] , i) , log[i] = log[i >> 1] + 1;
  81. dfs(1);
  82. scanf("%d" , &m);
  83. while(m -- )
  84. {
  85. scanf("%d" , &opt);
  86. if(opt == 1)
  87. {
  88. scanf("%s" , str) , t = 1 , tv = 0;
  89. for(i = 0 ; str[i] ; i ++ ) t = c[t][str[i] - 'a'] , val[++tv] = t;
  90. sort(val + 1 , val + tv + 1 , cmp);
  91. for(i = 1 ; i <= tv ; i ++ ) fix(vp[val[i]] , 1);
  92. for(i = 1 ; i < tv ; i ++ ) fix(vp[lca(val[i] , val[i + 1])] , -1);
  93. }
  94. else scanf("%d" , &x) , printf("%d\n" , query(lp[pos[x]]) - query(vp[pos[x]] - 1));
  95. }
  96. return 0;
  97. }

【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组的更多相关文章

  1. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  2. 【BZOJ】2819: Nim(树链剖分 / lca+dfs序+树状数组)

    题目 传送门:QWQ 分析 先敲了个树链剖分,发现无法AC(其实是自己弱,懒得debug.手写栈) 然后去学了学正解 核心挺好理解的,$ query(a) $是$ a $到根的异或和. 答案就是$ l ...

  3. Codeforces Round #200 (Div. 1) D Water Tree 树链剖分 or dfs序

    Water Tree 给出一棵树,有三种操作: 1 x:把以x为子树的节点全部置为1 2 x:把x以及他的所有祖先全部置为0 3 x:询问节点x的值 分析: 昨晚看完题,马上想到直接树链剖分,在记录时 ...

  4. BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]

    3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...

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

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

  6. BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)

    Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. “2 x” ...

  7. bzoj 3881: [Coci2015]Divljak AC自动机

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3881 题解: 这道题我想出了三种做法,不过只有最后一种能过. 第一种: 首先我们把所有的 ...

  8. BZOJ 3881[COCI2015]Divljak (AC自动机+dfs序+lca+BIT)

    显然是用AC自动机 先构建好AC自动机,当B中插入新的串时就在trie上跑,对于当前点,首先这个点所代表的串一定出现过,然后这个点指向的fail也一定出现过.那么我们把每个点fail当作父亲,建一棵f ...

  9. 【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1146 第一种做法(时间太感人): 第二种做法(rank5,好开心) ================ ...

随机推荐

  1. P2331 [SCOI2005]最大子矩阵

    题目描述 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 输入输出格式 输入格式: 第一行为n,m,k(1≤n≤100,1≤m≤2 ...

  2. 《Head First 设计模式》[01] 策略模式

    <Head First 设计模式>(点击查看详情) 1.写在前面的话 之前在列书单的时候,看网友对于设计模式的推荐里说,设计模式的书类别都大同小异,于是自己就选择了Head First系列 ...

  3. 将jar文件加到Maven的local repository中

    对于Maven项目来说,日常使用的多数第三方java库文件都可以从Maven的Central Repository中自动下载,但是如果我们需要的jar文件不在Central Repository中,那 ...

  4. 20155234 《网络对抗》Exp 8 Web基础

    基础问答 什么是表单 可以收集用户的信息和反馈意见,是网站管理者与浏览者之间沟通的桥梁. 表单包括两个部分:一部分是HTML源代码用于描述表单(例如,域,标签和用户在页面上看见的按钮),另一部分是脚本 ...

  5. 20155238 2016-2017-2 《JAVA程序设计》第九周学习总结

    教材学习内容总结 第十六章 JDBC SQL的解决方案是JDBC,在Java中,JDBC API主要用来存取数据库. *JDBC API是一个Java API,可以访问任何类型表列数据,特别是存储在关 ...

  6. 20155301 Exp6 信息搜集与漏洞扫描

    20155301 Exp6 信息搜集与漏洞扫描 实践内容 (1)各种搜索技巧的应用 (2)DNS IP注册信息的查询 (3)基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的查点 (4 ...

  7. python 单体模式 的几种实现

    这是本人的一篇学习笔记. 本文用 python 实现单体模式,参考了这里 一.修改父类的 __dict__ class Borg: _shared_state = {} def __init__(se ...

  8. 2_C语言中的数据类型 (十)数组

    1          字符串与字符数组 1.1       字符数组定义 char array[100]; 1.2       字符数组初始化 char array[100] = {'a', 'b', ...

  9. Spring Boot (十四): Spring Boot 整合 Shiro-登录认证和权限管理

    这篇文章我们来学习如何使用 Spring Boot 集成 Apache Shiro .安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求.在 Java 领域一般有 Spring S ...

  10. 软件测试 —— Bug

    [Bug规范] Bug标题中需包含Bug的具体位置并以[]标注 举例:[模块-子模块-页面]XXXXXXXXXXXX Bug标题尽量简明 做什么操作 + 出现什么结果,比如(点击提交按钮,出现卡顿现象 ...