AC自动机+树链剖分+线段树/树状数组+dfs序+树链的并

题意:给出n个母串和q个询问串,对于每个询问串输出有多少个母串包含这个询问串 N=∑|母串|<=10^5 Q=∑|询问串|<=3.6*10^5

由于是母串包含询问串,那么我们就对询问串建自动机,然后用母串在上面跑,跑一次的复杂度是母串的长度(不确定)

利用fail树的性质求解,每次母串跑到一个节点,就把这个节点到根的路径都加上1,说明母串当前匹配单词的一段后缀包含某个前缀,也就是母串包含某个前缀

由于是求出现次数,那么询问串多次出现在母串里只算一次,所以之前到根的路径上加重了,所以我们利用树链的并去重,将节点按dfs序排序,相邻两个节点的lca到根的路径-1,这样就使得每个节点到根的路径都等于1

然后就真写了一个树链剖分+单点查询,其实直接查子树就行了,直接在节点上打上+1标记,lca上打上-1标记,树状数组维护子树和就行了

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = ;
  4. int n, q;
  5. vector<char> v[N];
  6. char s[N];
  7. struct ac_automation {
  8. int root, cnt, tot, dfs_clock;
  9. int child[N][], fail[N], top[N], fa[N], son[N], dep[N], size[N], dfn[N], mir[N], tree[N << ], pos[N], tag[N << ];
  10. vector<int> G[N], p;
  11. void insert(char s[], int id)
  12. {
  13. int len = strlen(s), now = root;
  14. for(int i = ; i < len; ++i)
  15. {
  16. int t = s[i] - 'a';
  17. if(child[now][t] == ) child[now][t] = ++cnt;
  18. now = child[now][t];
  19. }
  20. pos[id] = now;
  21. }
  22. void build_fail()
  23. {
  24. queue<int> q;
  25. for(int i = ; i < ; ++i) if(child[root][i])
  26. {
  27. q.push(child[root][i]);
  28. G[root].push_back(child[root][i]);
  29. }
  30. while(!q.empty())
  31. {
  32. int u = q.front();
  33. q.pop();
  34. for(int i = ; i < ; ++i)
  35. {
  36. int &v = child[u][i];
  37. if(v == ) v = child[fail[u]][i];
  38. else
  39. {
  40. fail[v] = child[fail[u]][i];
  41. q.push(v);
  42. G[child[fail[u]][i]].push_back(v);
  43. }
  44. }
  45. }
  46. }
  47. int lca(int u, int v)
  48. {
  49. while(top[u] != top[v])
  50. {
  51. if(dep[top[u]] < dep[top[v]]) swap(u, v);
  52. u = fa[top[u]];
  53. }
  54. return dep[u] < dep[v] ? u : v;
  55. }
  56. void dfs(int u)
  57. {
  58. size[u] = ;
  59. for(int i = ; i < G[u].size(); ++i)
  60. {
  61. int v = G[u][i];
  62. dep[v] = dep[u] + ;
  63. fa[v] = u;
  64. dfs(v);
  65. size[u] += size[v];
  66. if(size[v] >= size[son[u]]) son[u] = v;
  67. }
  68. }
  69. void dfs(int u, int acs)
  70. {
  71. dfn[u] = ++dfs_clock;
  72. mir[dfn[u]] = u;
  73. top[u] = acs;
  74. if(son[u]) dfs(son[u], acs);
  75. for(int i = ; i < G[u].size(); ++i)
  76. {
  77. int v = G[u][i];
  78. if(v == son[u]) continue;
  79. dfs(v, v);
  80. }
  81. }
  82. void pushdown(int x, int l, int r)
  83. {
  84. if(tag[x] == ) return;
  85. int mid = (l + r) >> ;
  86. tag[x << ] += tag[x];
  87. tag[x << | ] += tag[x];
  88. tree[x << ] += tag[x] * (mid - l + );
  89. tree[x << | ] += tag[x] * (r - mid);
  90. tag[x] = ;
  91. }
  92. int query(int l, int r, int x, int pos)
  93. {
  94. if(l == r) return tree[x];
  95. pushdown(x, l, r);
  96. int mid = (l + r) >> ;
  97. if(pos <= mid) return query(l, mid, x << , pos);
  98. else return query(mid + , r, x << | , pos);
  99. }
  100. void update(int l, int r, int x, int a, int b, int delta)
  101. {
  102. if(l > b || r < a) return;
  103. if(l >= a && r <= b)
  104. {
  105. tag[x] += delta;
  106. tree[x] += (r - l + ) * delta;
  107. return;
  108. }
  109. pushdown(x, l, r);
  110. int mid = (l + r) >> ;
  111. update(l, mid, x << , a, b, delta);
  112. update(mid + , r, x << | , a, b, delta);
  113. tree[x] = tree[x << ] + tree[x << | ];
  114. }
  115. void change(int u, int delta)
  116. {
  117. while(top[u])
  118. {
  119. update(, cnt + , , dfn[top[u]], dfn[u], delta);
  120. u = fa[top[u]];
  121. }
  122. update(, cnt + , , , dfn[u], delta);
  123. }
  124. void put_string(int id)
  125. {
  126. int len = v[id].size(), now = root;
  127. p.clear();
  128. for(int i = ; i < len; ++i)
  129. {
  130. now = child[now][v[id][i] - 'a'];
  131. p.push_back(dfn[now]);
  132. }
  133. sort(p.begin(), p.end());
  134. p.erase(unique(p.begin(), p.end()), p.end());
  135. for(int i = ; i < p.size(); ++i)
  136. {
  137. int u = p[i];
  138. change(mir[u], );
  139. }
  140. for(int i = ; i < p.size(); ++i)
  141. {
  142. int u = p[i], v = p[i - ];
  143. change(lca(mir[u], mir[v]), -);
  144. }
  145. }
  146. int ask(int id)
  147. {
  148. return query(, cnt + , , dfn[pos[id]]);
  149. }
  150. } ac;
  151. int main()
  152. {
  153. scanf("%d%d", &n, &q);
  154. for(int i = ; i <= n; ++i)
  155. {
  156. scanf("%s", s);
  157. int len = strlen(s);
  158. for(int j = ; j < len; ++j) v[i].push_back(s[j]);
  159. }
  160. for(int i = ; i <= q; ++i)
  161. {
  162. scanf("%s", s);
  163. ac.insert(s, i);
  164. }
  165. ac.build_fail();
  166. ac.dfs();
  167. ac.dfs(, );
  168. for(int i = ; i <= n; ++i) ac.put_string(i);
  169. for(int i = ; i <= q; ++i) printf("%d\n", ac.ask(i));
  170. return ;
  171. }

bzoj2780的更多相关文章

  1. 【bzoj2780】 Sevenk Love Oimaster

    http://www.lydsy.com/JudgeOnline/problem.php?id=2780 (题目链接) 题意 给出很多主串和很多询问串,求一个询问串在多少主串中出现过 Solution ...

  2. 【BZOJ2780】【SPOJ】Sevenk Love Oimaster(后缀自动机)

    [BZOJ2780][SPOJ]Sevenk Love Oimaster(后缀自动机) 题面 BZOJ 洛谷 题解 裸的广义后缀自动机??? 建立广义后缀自动机建立出来之后算一下每个节点被几个串给包括 ...

  3. 【BZOJ2780】[Spoj]8093 Sevenk Love Oimaster 广义后缀自动机

    [BZOJ2780][Spoj]8093 Sevenk Love Oimaster Description Oimaster and sevenk love each other.     But r ...

  4. [bzoj2780][Spoj8093]Sevenk Love Oimaster_广义后缀自动机

    Sevenk Love Oimaster bzoj-2780 Spoj-8093 题目大意:给定$n$个大串和$m$次询问,每次给出一个字符串$s$询问在多少个大串中出现过. 注释:$1\le n\l ...

  5. BZOJ2780(广义后缀自动机,set启发式合并)

    BZOJ2780(广义后缀自动机,set启发式合并) 题面 自己找去 HINT 就是给多个文本串,然后每次查询的时候问你这个串在多少个文本串中出现过.因为多个文本串,那么直接就往广义后缀自动机上思考啊 ...

  6. BZOJ2780——[Spoj]8093 Sevenk Love Oimaster

    0.题意:给定N个原始字符串S,M次查询某个特殊的字符串S'在多少个原始串中出现过. 1.分析:这个题我们第一感觉就是可以用后缀自动机来搞,然后我们发现不是本质不同的字串..求出现过的次数,也就是说多 ...

  7. Bzoj2780: [Spoj]8093 Sevenk Love Oimaster

    题目 传送门 Sol 就是广义\(sam\) 然后记录下每个状态属于哪些串,开\(set\)维护 \(parent\)树上启发式合并一下就好了 # include <bits/stdc++.h& ...

  8. BZOJ2780:[SPOJ8093]Sevenk Love Oimaster(广义SAM)

    Description Oimaster and sevenk love each other. But recently,sevenk heard that a girl named ChuYuXu ...

  9. 【BZOJ2780】Sevenk Love Oimaster【广义后缀自动机】

    题意 给出你n个字符串和q个查询,每个查询给出一个字符串s,对于每个查询你都要输出这个字符串s在上面多少个字符串中出现过. 分析 广义后缀自动机的裸题.建好SAM以后再跑一遍得到每个状态的ocu和la ...

  10. [BZOJ2780][SPOJ8093]Sevenk Love Oimaster

    bzoj luogu 题面 给定n个模板串,以及m个查询串. 依次查询每一个查询串是多少个模板串的子串. sol 广义后缀自动机裸题? 先建出\(SAM\),然后记录一下每个节点分别在多少个模板串里出 ...

随机推荐

  1. 用Docker构建Tomcat镜像

    构建tomcat镜像 创建工作目录 [root@elk-node2 tomcat]# mkdir tomcat [root@elk-node2 tomcat]# cd tomcat [root@elk ...

  2. Leetcode加一 (java、python3)

    加一 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. Given ...

  3. NOIP 前的垂死挣扎

    计划每天十题吧,可能会一天水题一天难题吧.题目以杂题为主,没有专题可言. 10.11 计划: [x] P2939 [USACO09FEB] 改造路 Revamping Trails [ ] P3601 ...

  4. Python网络编程—socket(一)

    从今天开始python基础就介绍完毕了,下面我们将进阶到socket网络编程的介绍,那么socket是什么呢?我们带着这个问题开始今天的介绍: 一.socket初探 socket通常也称作" ...

  5. 【codeforces 3C】Tic-tac-toe

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 写一个函数判断当前局面是否有人赢. 然后枚举上一个人的棋子下在哪个地方. 然后把他撤回 看看撤回前是不是没人赢然后没撤回之前是不是有人赢了. ...

  6. qemu-guest-agent简介

    经常使用vmWare的同学都知道有vmware-tools这个工具,这个安装在vm内部的工具,可以实现宿主机与虚拟机的通讯,大大增强了虚拟机的性能与功能, 如vmware现在的Unity mode下可 ...

  7. 消息传递(cogs 1001)

    问题描述WZland开办了一个俱乐部(这里面可以干任何的事情),这引来了许多的人来加入.俱乐部的人数越来越多,关系也越来越复杂……俱乐部的人来自各个地方,为了增加友谊,俱乐部举行了一次晚会.晚会上又进 ...

  8. spring-quartz定时器简单用法

    基本配置: 1.quartz.properties #============================================================== #Configure ...

  9. redis+spring

    1. 在配置文件中添加 注解 <cache:annotation-driven cache-manager="cacheManager" key-generator=&quo ...

  10. 定义Portal显示规则

    Defining Portal Display Rules Use You use the Portal Display Rules editor to create and edit rule co ...