Divljak

Alice 有 $n$ 个字符串 $ S_1,S_2,\cdots,S_n $ ,Bob有一个字符串集合 $T$ ,一开始集合是空的。

接下来会发生 $q$ 个操作,操作有两种形式:

“ $1~P$ ”,Bob 往自己的集合里添加了一个字符串 $P$ 。

“ $2~x$ ”,Alice 询问 Bob,集合 $T$ 中有多少个字符串包含串 $S_x$ 。

(我们称串 $A$ 包含串 $B$ ,当且仅当 $B$ 是 $A$ 的子串)

Bob 遇到了困难,需要你的帮助。


Sol

考虑S集建AC自动机。

每次把新加入的串扔进去匹配,所有匹配位置加1。

查询时就是子树和。

但是有重复算的情况。我们把所有要加的点按dfs序排序,然后把相邻两两的lca-1

这样就不重了,lca之上的点会+2-1

卡常差评

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<algorithm>
  6. #include<cmath>
  7. #include<queue>
  8. #define maxn 2000006
  9. using namespace std;
  10. int num,n,tr[maxn][],fail[maxn],p[maxn],tot,cnt;
  11. int head[maxn],f[maxn],deep[maxn],dfn[maxn],sc;
  12. int son[maxn],sz[maxn],top[maxn],tree[maxn],a[maxn];
  13. struct node{
  14. int v,nex;
  15. }e[maxn*];
  16. char s[maxn];
  17. void ins(int id){
  18. int len=strlen(s),k=;
  19. for(int i=;i<len;i++){
  20. if(!tr[k][s[i]-'a'])tr[k][s[i]-'a']=++n;
  21. k=tr[k][s[i]-'a'];
  22. }
  23. p[id]=k;
  24. }
  25. void build(){
  26. queue<int>q;
  27. for(int i=;i<;i++)if(tr[][i])q.push(tr[][i]);
  28. while(!q.empty()){
  29. int k=q.front();q.pop();
  30. for(int i=;i<;i++){
  31. if(tr[k][i]){
  32. fail[tr[k][i]]=tr[fail[k]][i];
  33. q.push(tr[k][i]);
  34. }
  35. else tr[k][i]=tr[fail[k]][i];
  36. }
  37. }
  38. }
  39. void lj(int t1,int t2){
  40. e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
  41. }
  42. void dfs1(int k,int fa){
  43. f[k]=fa;deep[k]=deep[fa]+;
  44. sz[k]=;int gp=;
  45. for(int i=head[k];i;i=e[i].nex){
  46. dfs1(e[i].v,k);
  47. sz[k]+=sz[e[i].v];
  48. if(sz[e[i].v]>sz[gp] || !gp)gp=e[i].v;
  49. }
  50. son[k]=gp;
  51. }
  52. void dfs2(int k){
  53. dfn[k]=++sc;
  54. if(son[k])top[son[k]]=top[k],dfs2(son[k]);
  55. for(int i=head[k];i;i=e[i].nex)
  56. if(e[i].v!=son[k])top[e[i].v]=e[i].v,dfs2(e[i].v);
  57. }
  58. void add(int i,int v){
  59. for(;i<=n;i+=i&-i)tree[i]+=v;
  60. }
  61. int ask(int i){
  62. int sum=;for(;i;i-=i&-i)sum+=tree[i];
  63. return sum;
  64. }
  65. bool cmp(int a,int b){
  66. return dfn[a]<dfn[b];
  67. }
  68. int lca(int a,int b){
  69. int t1=top[a],t2=top[b];
  70. while(t1!=t2){
  71. if(deep[t1]<deep[t2])swap(t1,t2);
  72. a=f[t1],t1=top[a];
  73. }
  74. return deep[a]>deep[b]?b:a;
  75. }
  76. void work(){
  77. int tp=;
  78. int k=;int len=strlen(s);
  79. for(int i=;i<len;i++){
  80. k=tr[k][s[i]-'a'];a[++tp]=k;
  81. //add(dfn[k],1);
  82. }
  83. sort(a+,a+tp+,cmp);
  84. add(dfn[a[]],);
  85. for(int i=;i<=tp;i++)add(dfn[a[i]],),add(dfn[lca(a[i],a[i-])],-);
  86. }
  87. int main()
  88. {
  89. scanf("%d",&num);
  90. for(int i=;i<=num;i++){
  91. scanf(" %s",s);ins(i);
  92. }
  93. build();
  94.  
  95. for(int i=;i<=n;i++)lj(fail[i],i);
  96. n++;dfs1(,n);dfs2();
  97. int q;scanf("%d",&q);
  98. for(int i=,op;i<=q;i++){
  99. scanf("%d",&op);
  100. if(op==){
  101. scanf("%s",s);work();
  102. }
  103. else {
  104. int t;scanf("%d",&t);t=p[t];
  105. printf("%d\n",ask(dfn[t]+sz[t]-)-ask(dfn[t]-));
  106. }
  107. }
  108. return ;
  109. }

Divljak的更多相关文章

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

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

  2. 字符串(AC自动机):COCI 2015 round 5 divljak

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAy0AAANaCAIAAAALVTQoAAAgAElEQVR4nOy9X2hbx773PXfrQgQjDq

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

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

  4. BZOJ 3881: [Coci2015]Divljak

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

  5. 【BZOJ3881】[Coci2015]Divljak fail树+树链的并

    [BZOJ3881][Coci2015]Divljak Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操 ...

  6. BZOJ3881 : [Coci2015]Divljak

    对Alice的所有串构造AC自动机,并建出Fail树 每当Bob添加一个串时,在AC自动机上走,每走到一个点,就把它到根路径上所有点的答案+1 需要注意的是每次操作,相同的点只能被加一次 所以在需要操 ...

  7. [Coci2015]Divljak

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

  8. BZOJ3881 Divljak

    解:对被包含的那些串建AC自动机. 每次加一个串,就在AC自动机上面跑,可知能够跑到一些节点. 这些节点都是一些前缀的形式,我们跳fail树就是跳后缀,这样就能够得到所有能匹配的子串. 我们分别对AC ...

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

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

随机推荐

  1. input输入框类型

    输入大小写字母.数字.下划线: <input type="text" onkeyup="this.value=this.value.replace(/[^\w_]/ ...

  2. Typora -- 书写即美学

    #Typora -- 书写即美学 ##基本快捷键--需要在所见即所想界面进行输入 加粗 Ctrl + B 加粗 斜体 Ctrl + I 斜体 下划线 Ctrl + U 下划线 删除线 Ctrl + S ...

  3. 【Leetcode】413. Arithmetic Slices

    Description A sequence of number is called arithmetic if it consists of at least three elements and ...

  4. 2457: [BeiJing2011]双端队列

    2457: [BeiJing2011]双端队列 链接 很奇妙的转化. 题目要求最后的所有序列也是有序的,所以可以求出最后的序列(即排序后的序列),然后分成许多份,要求每一份都是一个双端序列,求最少分成 ...

  5. vuex的使用及持久化state的方式详解

    vuex的使用及持久化state的方式详解 转载  更新时间:2018年01月23日 09:09:37   作者:baby格鲁特    我要评论 这篇文章主要介绍了vuex的使用及持久化state的方 ...

  6. C++怎么用二维数组作为形参传入

    原文地址:http://blog.csdn.net/xuleicsu/article/details/919801 如何将二维数组作为函数的参数传递 今天写程序的时候要用到二维数组作参数传给一个函数, ...

  7. XPATH之normalize-space(.)和normalize-space(text())区别

    normalize,字面意思就是正规化,加上space大概意思就是空格的处理了. 官方解释是这样的: 通过去掉前导和尾随空白并使用单个空格替换一系列空白字符,使空白标准化.如果省略了该参数,上下文节点 ...

  8. 常用的python模块及安装方法

    adodb:我们领导推荐的数据库连接组件 bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheetahcherrypy:一个WEB frameworkctyp ...

  9. 接口测试工具postman(四)导入导出文件

    1.导入json文件 2.单个文件夹导出,文件格式是 json文件 3.所有数据导出,文件格式是 json文件

  10. Linux-ls,cd,type命令

    windows: dll:dynamic link library,动态链接库 Linux: .so:shared object,共享对象 操作系统: kernel:内核: 1.进程管理 2.内核管理 ...