题意:

1<=N<=10^5

1<=M<=10^5
输入总长<=10^5
 
思路:

From http://blog.csdn.net/lych_cys/article/details/50646799

首先你会发现他打字的方式非常奇妙。。实际上不就是在构建一颗Tire吗?P相当于给节点标记;B相当于退回父亲节点;a..z相当于建立新的节点。

然后跑AC自动机得到fail指针。

首先得知道如何得出单个操作x,y。在后缀数组(sam,后缀树等)中,判断u是v的子串的方法是看是否是每一个后缀的前缀;而AC自动机则架构在前缀树Tire上,自然地,判断AC自动机上面的两个子串u,v(AC自动机上的子串x可以看成是从根节点到节点x连成的一个字符串),u是否是v的子串,就等价于u是否是v某个前缀的后缀!在AC自动机上,判断u是x的后缀非常简单,只要看x能否沿着fail指针走到u即可。

那么,查询u在v中出现了几次就比较明了了,只要看从根节点到v的路径中有多少个x,满足u是x的后缀即x能沿着fail指针走到u。

于是,我们可以将fail[x]作为x(这里的x不同于上面的x)的父节点建立一颗新的树,这样的话如果i是j的祖先,那么j显然可以由fail指针走到i。那么查询u,v时,将root->v的路径上的每一个点都变为1,那么答案就相当于u的子树中有多少个1了。

但是这样直接在线查询显然不行(除非写一些高大上的数据结构)。单点修改子树查询可以用dfs序+树状数组解决,因此关键是减少修改次数。我们可以离线,以v为关键字排序,这样就可以根据原来建立AC自动机的顺序进行修改了,只要在进入一个点t时+1,出去时-1,查询时自然root->v的路径上的每一个点都是1了。

var map:array[..,..]of longint;
f,fa,ind,oud,q,t,x,y,id,head,vet,next,ans,num:array[..]of longint;
n,m,i,cnt,now,tot,j,k,len,time,u,que,tmp:longint;
ch:ansistring; procedure acauto;
var t,w,u,p,i,son:longint;
begin
t:=; w:=; q[]:=;
while t<w do
begin
inc(t); u:=q[t];
for i:= to do
if map[u,i]> then
begin
son:=map[u,i];
p:=f[u];
if u= then f[son]:=
else f[son]:=map[p,i];
inc(w); q[w]:=son;
end
else
begin
p:=f[u];
if u= then map[u,i]:=
else map[u,i]:=map[p,i];
end;
end;
end; procedure add(a,b:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
head[a]:=tot;
end; procedure dfs(u:longint);
var e,v:longint;
begin
inc(time); ind[u]:=time; oud[u]:=time;
e:=head[u];
while e<> do
begin
v:=vet[e];
if ind[v]= then
begin
dfs(v);
oud[u]:=oud[v];
end;
e:=next[e];
end;
end; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; procedure qsort(l,r:longint);
var i,j,t,mid:longint;
begin
i:=l; j:=r; mid:=y[(l+r)>>];
repeat
while mid>y[i] do inc(i);
while mid<y[j] do dec(j);
if i<=j then
begin
swap(x[i],x[j]);
swap(y[i],y[j]);
swap(id[i],id[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; function lowbit(x:longint):longint;
begin
exit(x and (-x));
end; procedure ins(x,y:longint);
begin
while x<=time do
begin
t[x]:=t[x]+y;
x:=x+lowbit(x);
end;
end; function query(x:longint):longint;
begin
query:=;
while x> do
begin
query:=query+t[x];
x:=x-lowbit(x);
end;
end; begin
assign(input,'bzoj2434.in'); reset(input);
assign(output,'bzoj2434.out'); rewrite(output);
readln(ch);
m:=length(ch); len:=; cnt:=; now:=;
for i:= to m do
begin
case ch[i] of
'P':
begin
inc(n); num[n]:=now;
continue;
end;
'B':
begin
now:=fa[now];
continue;
end;
end;
u:=ord(ch[i])-ord('a')+;
if map[now,u]= then
begin
inc(cnt); map[now,u]:=cnt;
fa[cnt]:=now;
end;
now:=map[now,u];
end; acauto;
for i:= to cnt do add(f[i],i);
dfs();
readln(que);
for i:= to que do
begin
read(x[i],y[i]);
id[i]:=i;
end;
qsort(,que);
j:=; k:=; now:=;
for i:= to m do
begin
case ch[i] of
'B':
begin
ins(ind[now],-); now:=fa[now];
continue;
end;
'P':
begin
inc(j);
while (k<=que)and(y[k]=j) do
begin
tmp:=num[x[k]];
ans[id[k]]:=query(oud[tmp])-query(ind[tmp]-);
inc(k);
end;
continue;
end;
end;
now:=map[now,ord(ch[i])-ord('a')+];
ins(ind[now],);
end;
for i:= to que do writeln(ans[i]);
close(input);
close(output);
end.

最新文章

  1. StringBuffer类的功能
  2. 处理ecshp图片上传失真
  3. python调用系统命令popen、system
  4. System.arraycopy
  5. Facebook或成云领域黑马 冲击亚马逊
  6. 矩形覆盖-我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
  7. 访问路径:https://i.cnblogs.com/posts?categoryid=925678
  8. K2 BPM + SAP,实现全方面管理企业
  9. Create CSS3 Buttons Compatible with All Browsers
  10. Linux gvim windows 版本配置
  11. 95秀-dialog 进度对话框 实用工具
  12. 获取IP地址(简单实现)
  13. plsql导入一个目录下全部excel
  14. php 删除指定文件夹
  15. SPRINGBOOT 读书笔记
  16. Angularjs实现select的下拉列表
  17. python 操作系统模块 -- OS
  18. C# 获取本机的所有ip地址,并过滤内网ip
  19. spring3.0.6+hibernate3升级spring4.1.6+hibernate4.3遇到的问题
  20. 不同复制模式下,如何忽略某些binlog事件

热门文章

  1. G - And Then There Was One (约瑟夫环变形)
  2. 启动tomcat报错:ImageFormatException
  3. 238 Product of Array Except Self 除自身以外数组的乘积
  4. Java多线程——线程之间的同步
  5. 1102 A-B数对
  6. js this 和 event 的区别
  7. Spark学习之RDD编程(2)
  8. PHP开发心得四
  9. tomcat 访问IP直接访问项目
  10. HDU_1024_dp