zoukankan      html  css  js  c++  java
  • 【BZOJ2434】阿狸的打字机(fail树,DFS序)

    题意:

    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[0..150000,1..26]of longint;
        f,fa,ind,oud,q,t,x,y,id,head,vet,next,ans,num:array[1..150000]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:=0; w:=1; q[1]:=1;
     while t<w do
     begin
      inc(t); u:=q[t];
      for i:=1 to 26 do
       if map[u,i]>0 then
       begin
        son:=map[u,i];
        p:=f[u];
        if u=1 then f[son]:=1
         else f[son]:=map[p,i];
        inc(w); q[w]:=son;
       end
        else
        begin
         p:=f[u];
         if u=1 then map[u,i]:=1
          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<>0 do
     begin
      v:=vet[e];
      if ind[v]=0 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)>>1];
     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:=0;
     while x>0 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:=0; cnt:=1; now:=1;
     for i:=1 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')+1;
      if map[now,u]=0 then
      begin
       inc(cnt); map[now,u]:=cnt;
       fa[cnt]:=now;
      end;
      now:=map[now,u];
     end;
    
    
     acauto;
     for i:=2 to cnt do add(f[i],i);
     dfs(1);
     readln(que);
     for i:=1 to que do
     begin
      read(x[i],y[i]);
      id[i]:=i;
     end;
     qsort(1,que);
     j:=0; k:=1; now:=1;
     for i:=1 to m do
     begin
      case ch[i] of
       'B':
       begin
        ins(ind[now],-1); 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]-1);
         inc(k);
        end;
        continue;
       end;
      end;
      now:=map[now,ord(ch[i])-ord('a')+1];
      ins(ind[now],1);
     end;
     for i:=1 to que do writeln(ans[i]);
     close(input);
     close(output);
    end.
  • 相关阅读:
    Go:错误处理
    Go:闭包
    Go:内置函数
    Go:函数、defer
    mongodb 在PHP中常见问题及解决方法
    PHP 下载apk文件
    阿里云短信服务 PHP
    tp 创建文件并写入数据
    微信小程序中的加载更多(即列表分页)
    百度地图api逆地址解析 PHP
  • 原文地址:https://www.cnblogs.com/myx12345/p/6700098.html
Copyright © 2011-2022 走看看