SAM好题,显然我们不能与每个后缀都去算LCP

考虑对询问串每一位算贡献,先构建出逆序构建自动机,这样我们得到了原串的后缀树(parent树)

根据parent树的定义,一个节点对应字符串出现的位置对应该节点的right集合也就是子树right集合的并

某些节点代表了一个后缀,我们从开头到结尾编号为1~n;这样求出每个节点的子树内,代表后缀的节点所代表的后缀编号最小是多少,记作mi[]

然后对于每个询问串在自动机上匹配(逆序),设最终匹配到的点为x

由于每个子串一定是某个后缀的某个前缀

如果匹配成功了,说明匹配到mi[x]这个后缀就结束了,否则会一直匹配下去,我们假设匹配到n+1结束

设最终匹配到的后缀为m,显然,从x到root上我们计算每条边的贡献

对于边(fa[a],a),边上的每个字符的比较次数贡献显然就是a子树内代表后缀编号小于等于m的节点个数

裸的想法可以用dfs序+主席树来完成

最后我们答案还要+x-1,因为比较失败也算是一次比较……

  1. type node=record
  2. po,next:longint;
  3. end;
  4. point=record
  5. l,r,s:longint;
  6. end;
  7.  
  8. var tree:array[..*] of point;
  9. e:array[..] of node;
  10. go:array[..,''..''] of longint;
  11. mi,b,h,p,l,r,fa,mx,w:array[..] of longint;
  12. cl,n,m,x,y,i,j,k,last,t,len:longint;
  13. fl:boolean;
  14. s:ansistring;
  15. ans:int64;
  16.  
  17. function lowbit(x:longint):longint;
  18. begin
  19. exit(x and (-x));
  20. end;
  21.  
  22. function min(a,b:longint):longint;
  23. begin
  24. if a>b then exit(b) else exit(a);
  25. end;
  26.  
  27. procedure ins(x,y:longint);
  28. begin
  29. inc(len);
  30. e[len].po:=y;
  31. e[len].next:=p[x];
  32. p[x]:=len;
  33. end;
  34.  
  35. procedure add(c:char);
  36. var p,q,np,nq:longint;
  37. begin
  38. p:=last;
  39. inc(t); np:=t; last:=t;
  40. mx[np]:=mx[p]+;
  41. w[np]:=i;
  42. while (p<>) and (go[p,c]=) do
  43. begin
  44. go[p,c]:=np;
  45. p:=fa[p];
  46. end;
  47. if p= then fa[np]:=
  48. else begin
  49. q:=go[p,c];
  50. if mx[q]=mx[p]+ then fa[np]:=q
  51. else begin
  52. inc(t); nq:=t;
  53. mx[nq]:=mx[p]+;
  54. go[nq]:=go[q];
  55. fa[nq]:=fa[q];
  56. fa[q]:=nq; fa[np]:=nq;
  57. while go[p,c]=q do
  58. begin
  59. go[p,c]:=nq;
  60. p:=fa[p];
  61. end;
  62. end;
  63. end;
  64. end;
  65.  
  66. procedure dfs(x:longint);
  67. var i,y:longint;
  68. begin
  69. inc(len);
  70. b[len]:=x;
  71. mi[x]:=w[x];
  72. if w[x]= then mi[x]:=;
  73. // writeln(x,' ',fa[x],':',w[x]);
  74. l[x]:=len;
  75. i:=p[x];
  76. while i<> do
  77. begin
  78. y:=e[i].po;
  79. dfs(y);
  80. mi[x]:=min(mi[x],mi[y]);
  81. i:=e[i].next;
  82. end;
  83. r[x]:=len;
  84. // writeln(mi[x]);
  85. end;
  86.  
  87. function build(l,r:longint):longint;
  88. var m,q:longint;
  89. begin
  90. inc(len);
  91. if l=r then exit(len)
  92. else begin
  93. q:=len;
  94. m:=(l+r) shr ;
  95. tree[q].l:=build(l,m);
  96. tree[q].r:=build(m+,r);
  97. exit(q);
  98. end;
  99. end;
  100.  
  101. function work(l,r,last,x:longint):longint;
  102. var m,q:longint;
  103. begin
  104. inc(len);
  105. q:=len;
  106. if l=r then tree[q].s:=tree[last].s+
  107. else begin
  108. m:=(l+r) shr ;
  109. if x<=m then
  110. begin
  111. tree[q].r:=tree[last].r;
  112. tree[q].l:=work(l,m,tree[last].l,x);
  113. end
  114. else begin
  115. tree[q].l:=tree[last].l;
  116. tree[q].r:=work(m+,r,tree[last].r,x);
  117. end;
  118. tree[q].s:=tree[tree[q].l].s+tree[tree[q].r].s;
  119. end;
  120. exit(q);
  121. end;
  122.  
  123. function ask(l,r,p,q:longint):longint;
  124. var m:longint;
  125. begin
  126. if (x>=r) then exit(tree[q].s-tree[p].s)
  127. else begin
  128. m:=(l+r) shr ;
  129. if x<=m then exit(ask(l,m,tree[p].l,tree[q].l))
  130. else exit(tree[tree[q].l].s-tree[tree[p].l].s+ask(m+,r,tree[p].r,tree[q].r));
  131. end;
  132. end;
  133.  
  134. begin
  135. readln(n);
  136. readln(s);
  137. last:=; t:=;
  138. for i:=n downto do
  139. add(s[i]);
  140. for i:= to t do
  141. if fa[i]<> then ins(fa[i],i);
  142. len:=;
  143. dfs();
  144. readln(m);
  145. len:=;
  146. h[]:=build(,n);
  147. for i:= to t do
  148. if w[b[i]]= then h[i]:=h[i-]
  149. else h[i]:=work(,n,h[i-],w[b[i]]);
  150. for i:= to m do
  151. begin
  152. readln(s);
  153. len:=length(s);
  154. j:=;
  155. fl:=true;
  156. cl:=;
  157. for k:=len downto do
  158. if go[j,s[k]]= then
  159. begin
  160. while (go[j,s[k]]=) and (j>) do
  161. begin
  162. j:=fa[j];
  163. cl:=mx[j];
  164. end;
  165. if j= then j:=
  166. else begin
  167. inc(cl);
  168. j:=go[j,s[k]];
  169. end;
  170. fl:=false;
  171. end
  172. else begin
  173. inc(cl);
  174. j:=go[j,s[k]];
  175. end; //cl表示询问串从头开始最长匹配的长度
  176. if fl then x:=mi[j] else x:=n+;
  177. ans:=;
  178. if j> then
  179. begin
  180. y:=cl-mx[fa[j]]; // 这里要注意
  181. ans:=ans+int64(y)*int64(ask(,n,h[l[j]-],h[r[j]]));
  182. j:=fa[j];
  183. end;
  184. while j> do
  185. begin
  186. y:=mx[j]-mx[fa[j]];
  187. ans:=ans+int64(y)*int64(ask(,n,h[l[j]-],h[r[j]]));
  188. j:=fa[j];
  189. end;
  190. writeln(ans+x-);
  191. end;
  192. end.

bzoj3413的更多相关文章

  1. 【BZOJ3413】匹配(后缀自动机,线段树合并)

    [BZOJ3413]匹配(后缀自动机,线段树合并) 题面 BZOJ 题解 很好的一道题目. 做一个转化,匹配的次数显然就是在可以匹配的区间中,每个前缀的出现次数之和. 首先是空前缀的出现次数,意味着你 ...

  2. 【BZOJ3413】匹配 离线+后缀树+树状数组

    [BZOJ3413]匹配 Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一 ...

  3. BZOJ3413 : 匹配

    FDUSC前刷刷题吧.. 本题每个询问就是说将询问串与主串每个后缀匹配,若匹配成功则结束,否则加上lcp的长度 对主串建立后缀树,并用主席树维护DFS序 对于每个询问串,找到最后走到的点fin_nod ...

  4. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  5. BZOJ3413: 匹配(后缀自动机,Parent树,线段树合并)

    Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一个由0到9组成的字符串s, ...

随机推荐

  1. 模仿开发H5游戏,看你有多色

    开发记录 前言 之前跟着慕课网学习开发H5小游戏开心鱼,勾起我的兴趣. 在写代码的过程中,不怎么会遇到问题.虽然代码是亲手敲出来的,但是由于并没有对游戏的整体思路,所以并不知道开发与优化的过程. 为了 ...

  2. JavaScript string array 数组

    Array类可以如下定义: var aValues = new Array(); 如果预先知道数组的长度,可以用参数传递长度 var aValues = new Array(20); -------- ...

  3. centos 虚拟机安装过程

    centos装过好几次了,也装过好几次fedora,感觉centos更灵活些,这次我装了最简洁的centos,然后通过yum命令安装了各种需要的命令和软件,编译了phpredis.redis.和php ...

  4. POJ 3723 Conscription 最小生成树

    题目链接: 题目 Conscription Time Limit: 1000MS Memory Limit: 65536K 问题描述 Windy has a country, and he wants ...

  5. DIV+CSS高手必知的15个CSS常识

    1.不要使用过小的图片做背景平铺.这就是为何很多人都不用 1px 的原因,这才知晓.宽高 1px 的图片平铺出一个宽高 200px 的区域,需要 200*200=40, 000 次,占用资源. 2.无 ...

  6. Bootstrap 基础

    一种前端开发框架,如同YUI 下载源码找开后,其文件结构如下: bootstrap/├── css/│   ├── bootstrap.css│   ├── bootstrap.min.css│   ...

  7. GetSurfaceLevel

      if( SUCCEEDED( g_pTexture->GetSurfaceLevel( 0, &pSurface) ) )    {        pd3dDevice->Se ...

  8. 指针强转和void*

    C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值.不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个地址就是硬件访问的依据,而名字只是提供给程序员的 ...

  9. [原] GLES在iOS和Android上的不同

    本来GLES提供了与native platform的接口 EGL, 然而iOS没有使用EGL接口, 而是自己搞了一套,叫做EAGL的类似东西, 虽然说大同小异,但是在做跨平台的时候还是很恶心. elg ...

  10. PHP之session相关实例教程与经典代码

    ·php 中cookie和session的用法比较 ·phpmyadmin报错:Cannot start session without errors问题 ·php中cookie与session应用学 ...