这道题由于读入的字符串长度可能很大,不能一个一个字符串插入trie图。
又因为一个字符串形成以后字母不会消失,于是便可以一边读入一边建trie图。
然后,由于fail指针指向最长后缀,就可以将fail指针改变方向得到一棵fail树(因为每个点的出度为1,改了方向以后入度也为1)。在fail树中,一个单词节点的子树有多少个节点就代表这个单词在其他单词中出现了多少次。
如何快速查询一个节点的子树中有多少目标节点呢?
显然,先标记目标节点再用dfs先序遍历加树状数组这种O(nlogn)级别的方法比较快。
面对题目里如此大量的询问,离线做法会快很多。
但是如果一个字符串一个字符串地标记很明显会超时,怎么办呢?
联想到前面建trie图的做法,于是得到一个比较好的方法:
读入一个字母就在树状数组中相应的位置加1,删去一个字母就减1;遇到‘P’就处理y为当前字符串的询问。
这道题就可以解决了。
代码:
{$inline on}
type
zy=record
next:longint;
ch:char;
end;
var
wei,l,r,a,d,fa:array [0..100000]of longint;
pre3,now3,son3,poss,pre2,now2,son2,pos,pre,now,son:array[0..100000]of longint;
tree:array[0..80000]of zy;
ss:array[0..100000]of char;
ans:array[0..100000] of longint;
sum,num,xx,w,lengg,p,x,leng,tot,tott,n,i,j,k:longint;
chh:char;
procedure insert(a:longint;chh:char);inline;//建trie图的边
begin
inc(tot); inc(tott);
pre[tot]:=now[a];
now[a]:=tot;
son[tot]:=tott;
tree[tott].ch:=chh;
fa[tott]:=a;
end;
procedure insert2(a,b:longint);inline;//建fail树的边
begin
inc(tot);
pre2[tot]:=now2[a];
now2[a]:=tot;
son2[tot]:=b;
end;
function check(x:longint;chh:char):longint;inline;//找到x的chh儿子
var
p:longint;
begin
p:=now[x];
while p<>0 do
begin
if tree[son[p]].ch=chh then
exit(son[p]);
p:=pre[p];
end;
exit(0);
end;
procedure bfs;inline;//建trie图
var
kk,ffa,x,p,t,w,i,j,k:longint;
begin
d[1]:=1; t:=1; w:=1;tree[1].next:=1;
while t<=w do
begin
x:=d[t];
p:=now[x];
while p<>0 do
begin
inc(w);
d[w]:=son[p];
p:=pre[p];
end;
if x<>1 then
begin
ffa:=fa[x];
while ffa<>1 do
begin
k:=check(tree[ffa].next,tree[x].ch);
if k<>0 then
begin
tree[x].next:=k;
insert2(k,x);
break;
end;
ffa:=tree[ffa].next;
end;
if ffa=1 then
begin
tree[x].next:=1;
insert2(1,x);
end;
end;
inc(t);
end;
end;
procedure dfs(x,fa:longint);//得出dfs序
var
ll,rr,p:longint;
begin
p:=now2[x];
inc(w); pos[x]:=w;
l[x]:=w;
while p<>0 do
begin
if son2[p]<>fa then
dfs(son2[p],x);
p:=pre2[p];
end;
r[x]:=w;
end;
function lowbit(x:longint):longint;inline;
begin
exit(x and(-x));
end;
function find(x:longint):longint;inline;
var
ans:longint;
begin
ans:=0;
while x>0 do
begin
ans:=ans+a[x];
x:=x-lowbit(x);
end;
exit(ans);
end;
procedure add(x,v:longint);inline;
begin
while x<=tott do
begin
a[x]:=a[x]+v;
x:=x+lowbit(x);
end;
end;
begin
tott:=1; x:=1;
while not eoln do
begin
read(chh);
inc(lengg);
ss[lengg]:=chh;
if (chh<='z')and(chh>='a') then
begin
j:=check(x,chh);
if j=0 then
begin
insert(x,chh);
x:=tott;
end
else
x:=j;
end
else
if chh='B' then
x:=fa[x]
else
begin
inc(sum);
wei[sum]:=x;
end;
end;
tot:=0;
bfs;
dfs(1,0);
readln;
readln(n);
for i:=1 to n do
poss[i]:=i;
for i:=1 to n do
begin
readln(j,k);
son3[i]:=j; pre3[i]:=now3[k]; now3[k]:=i;
end;
x:=1; num:=0;
for i:=1 to lengg do
begin
if (ss[i]<='z')and(ss[i]>='a') then
begin
x:=check(x,ss[i]);
add(pos[x],1);
end
else
if ss[i]='B' then
begin
add(pos[x],-1);
x:=fa[x];
end
else
begin
inc(num); j:=now3[num];
while j<>0 do
begin
ans[j]:=find(r[wei[son3[j]]])-find(l[wei[son3[j]]]-1);
j:=pre3[j];
end;
end;
end;
for i:=1 to n do
writeln(ans[i]);
end.