要点

  • 显然ac自动机的板子就可以暴力一下答案了
  • 为了优化时间复杂度,考虑套路fail树的dfs序。发现本题需要当前这个尾点加上所有祖先点的个数,考虑使用树状数组差分一下,在父点+1,在子树后-1,每次询问前缀和即可
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <sstream>
  6. #include <string>
  7. #include <vector>
  8. #include <queue>
  9. using namespace std;
  10. typedef long long ll;
  11. const int N = 1e6 + 5, maxk = 1e5 + 5;
  12. int n, k, pos[maxk], in[maxk];
  13. string s, t;
  14. struct FenwickTree {
  15. ll F[N];
  16. void Modify(int x, int val) {
  17. for (; x < N; x += x&-x)
  18. F[x] += val;
  19. }
  20. ll Query(int x) {
  21. ll res = 0;
  22. for (; x; x -= x&-x)
  23. res += F[x];
  24. return res;
  25. }
  26. }bit;
  27. struct Aho_Corasick_Automaton {
  28. int ch[N][26];//Trie树的转移
  29. //int val[N];//根据题意赋值。有值则意味着某子串末尾
  30. int fail[N];//失配,转移到别的树枝接着找
  31. int sz;//注意这个板子sz一定是要从1开计
  32. vector<int> adj[N];//用于fail树
  33. int dfn[N], Time, size[N];
  34. void insert(string s, int id) {//Trie的插入
  35. int len = s.length(), now = 0;
  36. for (int i = 0; i < len; i++){
  37. int c = s[i] - 'a';
  38. if (!ch[now][c]) {
  39. sz++;
  40. memset(ch[sz], 0, sizeof ch[sz]);
  41. //val[sz] = 0;
  42. ch[now][c] = sz;
  43. }
  44. now = ch[now][c];
  45. }
  46. //val[now] = id;
  47. pos[id] = now;
  48. }
  49. void getfail(){
  50. queue<int> Q;
  51. for (int i = 0; i < 26; i++)
  52. if (ch[0][i]) {
  53. adj[0].emplace_back(ch[0][i]);
  54. fail[ch[0][i]] = 0, Q.push(ch[0][i]);//第二层指向根
  55. }
  56. while (!Q.empty()){
  57. int u = Q.front(); Q.pop();
  58. for (int i = 0; i < 26; i++)
  59. if (ch[u][i]) {
  60. adj[ch[fail[u]][i]].emplace_back(ch[u][i]);
  61. fail[ch[u][i]] = ch[fail[u]][i], Q.push(ch[u][i]);//指向其他枝上同样的字母
  62. }
  63. else ch[u][i] = ch[fail[u]][i];//使得find时半路突然失配时还能一下拐回去
  64. }
  65. }
  66. void dfs(int u) {
  67. dfn[u] = ++Time;
  68. size[u] = 1;
  69. for (int v : adj[u]) {
  70. dfs(v);
  71. size[u] += size[v];
  72. }
  73. }
  74. int find(string T){
  75. int len = T.length(), now = 0;
  76. ll res = 0;
  77. for (int i = 0; i < len; i++){
  78. now = ch[now][T[i] - 'a'];
  79. res += bit.Query(dfn[now]);
  80. // for (int t = now; t; t = fail[t])//事实上这是一个不断缩短后缀的过程
  81. // if (val[t]) res++;
  82. }
  83. return res;
  84. }
  85. }ac;
  86. int calc(string t) {
  87. stringstream ss(t);
  88. int x; ss >> x;
  89. return x;
  90. }
  91. int main() {
  92. ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  93. cin >> n >> k;
  94. for (int i = 1; i <= k; i++) {
  95. cin >> s;
  96. ac.insert(s, i);
  97. in[i] = 1;
  98. }
  99. ac.getfail();
  100. ac.dfs(0);
  101. for (int i = 1; i <= k; i++) {
  102. int id = pos[i];
  103. bit.Modify(ac.dfn[id], 1);
  104. bit.Modify(ac.dfn[id] + ac.size[id], -1);
  105. }
  106. for (int i = 0; i < n; i++) {
  107. cin >> t;
  108. char x = t[0]; t.erase(0, 1);
  109. if (x == '+') {
  110. int v = calc(t);
  111. if (!in[v]) {
  112. int id = pos[v];
  113. bit.Modify(ac.dfn[id], 1);
  114. bit.Modify(ac.dfn[id] + ac.size[id], -1);
  115. in[v] = 1;
  116. }
  117. } else if (x == '-') {
  118. int v = calc(t);
  119. if (in[v]) {
  120. int id = pos[v];
  121. bit.Modify(ac.dfn[id], -1);
  122. bit.Modify(ac.dfn[id] + ac.size[id], 1);
  123. in[v] = 0;
  124. }
  125. } else {
  126. cout << ac.find(t) << '\n';
  127. }
  128. }
  129. }

Codeforces 163E(ac自动机、树状数组)的更多相关文章

  1. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

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

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

  3. Codeforces 587F - Duff is Mad(根号分治+AC 自动机+树状数组)

    题面传送门 第一眼看成了 CF547E-- 话说 CF587F 和 CF547E 出题人一样欸--还有另一道 AC 自动机的题 CF696D 也是这位名叫 PrinceOfPersia 的出题人出的- ...

  4. Codeforces 547E - Mike and Friends(AC 自动机+树状数组)

    题面传送门 好久每做过 AC 自动机的题了--做几个题回忆一下罢 AC 自动机能够解决多串匹配问题,注意是匹配,碰到前后缀的问题那多半不在 AC 自动机能解决的范围内. 在初学 AC 自动机的时候相信 ...

  5. CoderForces 163E e-Government(AC自动机+树状数组维护fail树的dfs序)

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

  6. BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)

    Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4140  Solved: 2276[Submit][Status][Discuss] Descript ...

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

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

  8. HDU 6096 String(AC自动机+树状数组)

    题意 给定 \(n\) 个单词,\(q\) 个询问,每个询问包含两个串 \(s_1,s_2\),询问有多少个单词以 \(s_1\) 为前缀, \(s_2\) 为后缀,前后缀不能重叠. \(1 \leq ...

  9. bzoj 2434 AC自动机+树状数组

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

  10. [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组

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

随机推荐

  1. L88

    Where You Vote May Affect How You Vote On election day, where do you vote? If it's in a church, you ...

  2. leetcode 169. Majority Element 多数投票算法(Boyer-Moore Majority Vote algorithm)

    题目: Given an array of size n, find the majority element. The majority element is the element that ap ...

  3. [Shell]Tetris Game

    这篇文章主要介绍Shell脚本编写俄罗斯方块的方法,原文来自脚本之家,http://www.jb51.net/article/48926.htm 效果图: 代码: #!/bin/bash # Tetr ...

  4. Android的appium实例

    1.查看Android的应用包名和activity的方法   (网上有很多种方法,这里应用的是查看日志的方法) CMD中输入>adb logcat -c                   &g ...

  5. Restore Points 制定回退方案

    Restore Points 制定回退方案 背景:Flashback Database 和 restore points 都可以提供一个基于时间点的回滚. 理论:1) Normal Restore P ...

  6. Scala学习——操作符(初)

    经常看到却反应不出来的(->) val a = 2 val b = a->4 //表示生成一个tuple println(b._1+" "b._2) //2 4

  7. 分布式一致性协议之:Zab(Zookeeper的分布式一致性算法)

    Zookeeper使用了一种称为Zab(Zookeeper Atomic Broadcast)的协议作为其一致性复制的核心,据其作者说这是一种新发算法,其特点是充分考虑了Yahoo的具体情况:高吞吐量 ...

  8. 【转】STL中的set容器的一点总结

    转自 http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/13/2636375.html 1.关于set C++ STL 之所以得到广泛的赞誉,也 ...

  9. java去任意范围的随机数

    一.java.uitl.Randomrandom.nextInt(20),任意取[0,20)之间整数,其中0可以取到,20取不到 二.取某个范围的任意数public static String get ...

  10. Arduino 视频教程

    http://v.youku.com/v_show/id_XNDU1MjI4MzA4.html?from=y1.2-1-176.3.12-2.1-1-1-11