bzoj-2434: [Noi2011]阿狸的打字机

11 篇文章 0 订阅
6 篇文章 0 订阅

2434: [Noi2011]阿狸的打字机

Time Limit: 10 Sec   Memory Limit: 256 MB
Submit: 1016   Solved: 572
[ Submit][ Status]

Description

 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。

经阿狸研究发现,这个打字机是这样工作的:

l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。

l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。

l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。

例如,阿狸输入aPaPBbP,纸上被打印的字符如下:

a

aa

ab

我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。

阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

Input

 输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

第二行包含一个整数m,表示询问个数。

接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

Output

 输出m行,其中第i行包含一个整数,表示第i个询问的答案。

Sample Input

aPaPBbP

3

1 2

1 3

2 3

Sample Output

2

1

0

HINT

 1<=N<=10^5


1<=M<=10^5

输入总长<=10^5

    ......这题调了一个晚上。。虽然并不复杂,但写起来各种小错误>_<
    先构图建AC自动机,然后把FAIL边倒过来,这样询问I J 就成了查询已I为根的子树中有几个点是J的。。。。
   求出FAIL树的DFS序后,I的子树的编号是连续的,所以用树状数组维护就行了。。GG
   /*/今天换了个新鼠标,用起来蛮顺的,还送了个很好玩的清洁果冻(像是果冻)。。马上就又要去郑州集训了。。
   又要被各种犇虐了,好感动,一年了,现在我已不再那么浮躁了,NOI 2014 加油。  /*/   /*/陈年旧事  /*/

var
i,j,k,tot,num,zs,time,now,p,m,x,y:longint;
c:char;
trie:array [0..500000,'a'..'z'] of longint;
s:ansistring;
a,ans,f,rd,cd,d,fal,z,fa:array [0..1000000] of longint;
b:array [0..1000000,1..3] of longint;
procedure inser(k,x:longint);
var
p:longint;
begin
p:=k;
while p<=length(s)+1 do
  begin
   inc(f[p],x);
   p:=p+p and (-p);
  end;
end;
function sum(k:longint):longint;
var
p:longint;
begin
p:=k;
sum:=0;
while p<>0 do
  begin
   inc(sum,f[p]);
   p:=p-p and (-p);
  end;
end;
procedure insert(x,y:longint);
begin
inc(num);
b[num,1]:=y;
b[num,2]:=a[x];
a[x]:=num;
end;
procedure insertt(x,y,tob:longint);
begin
inc(num);
b[num,1]:=y;
b[num,2]:=a[x];
b[num,3]:=tob;
a[x]:=num;
end;
procedure dfs(k:longint);
var
p,j:longint;
begin
inc(time);
rd[k]:=time;
p:=a[k];
while p<>0 do
  begin
   j:=b[p,1];
   dfs(j);
   p:=b[p,2];
  end;
cd[k]:=time;
end;
begin
readln(s);
zs:=1;
for i:=1 to length(s) do
  if s[i]='P' then
   begin
    d[zs]:=tot;
    inc(zs);
   end
              else
   if s[i]='B' then now:=fa[now] else
      if trie[now,s[i]]<>0 then now:=trie[now,s[i]]
                           else
       begin
        inc(tot);
        trie[now,s[i]]:=tot;
        fa[tot]:=now;
        now:=tot;
       end;
z[1]:=0;
i:=1;
j:=2;
while (z[i]<>0) or (i=1) do
  begin
   for c:='a' to 'z' do
    if trie[z[i],c]<>0 then
     begin
      z[j]:=trie[z[i],c];
      p:=fal[z[i]];
      while (trie[p,c]=0)and(p<>0) do
       p:=fal[p];
      if z[i]<>0 then fal[z[j]]:=trie[p,c]
                 else fal[z[j]]:=0;
      insert(fal[z[j]],z[j]);
      inc(j);
     end;
   inc(i);
  end;
dfs(0);
read(m);
num:=0;
fillchar (a,sizeof(a),0);
fillchar (b,sizeof(b),0);
for i:=1 to m do
  begin
   read(x,y);
   insertt(y,x,i);
  end;
zs:=1;
now:=0;
for i:=1 to length(s) do
  if s[i]='P' then
  begin
   p:=a[zs];
   while p<>0 do
    begin
     j:=b[p,1];
     if b[p,3]=1 then
      write;
     ans[b[p,3]]:=sum(cd[d[j]])-sum(rd[d[j]]-1);
     p:=b[p,2];
    end;
   inc(zs);
  end
              else
   if s[i]='B' then
    begin
     inser(rd[now],-1);
     now:=fa[now];
    end
               else
      begin
       now:=trie[now,s[i]];
       inser(rd[now],1);
      end;
for i:=1 to m do
  writeln(ans[i]);
end.


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值