zoukankan      html  css  js  c++  java
  • BZOJ4231 : 回忆树

    一个长度为$|S|$的串在树上匹配有两种情况:

    1.在LCA处转弯,那么这种情况只有$O(|S|)$次,暴力提取出长度为$2|S|$的链进行KMP即可。

    2.不转弯,那么可以拆成两个到根路径的询问。

    对所有串的正反串建立AC自动机,求出fail树上每个点的DFS序。

    然后DFS原树,记录在AC自动机上走到了哪个点,在那个点$+1$,回溯的时候$-1$。

    那么一个询问的答案就是fail树上的子树和,树状数组维护即可。

    时间复杂度$O(nlog n+|S|)$。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=100010,M=600010;
    char a[M],b[N];
    int n,m,len,i,j,x,y,z,g[N],v[N<<1],w[N<<1],nxt[N<<1],ed,G[N],V[N<<2],W[N<<2],NXT[N<<2];
    int size[N],son[N],f[N],fs[N],d[N],top[N],loc[N],seq[N],dfn,ans[N];
    inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
    inline void ADD(int x,int y,int z){V[++ed]=y;W[ed]=z;NXT[ed]=G[x];G[x]=ed;}
    void dfs(int x){
      size[x]=1;
      for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
        f[v[i]]=x,fs[v[i]]=w[i],d[v[i]]=d[x]+1;
        dfs(v[i]),size[x]+=size[v[i]];
        if(size[v[i]]>size[son[x]])son[x]=v[i];
      }
    }
    void dfs2(int x,int y){
      seq[loc[x]=++dfn]=x;top[x]=y;
      if(son[x])dfs2(son[x],y);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
    }
    inline int lca(int x,int y){
      for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
      return d[x]<d[y]?x:y;
    }
    inline int kth(int x,int y){
      while(d[x]-d[top[x]]<y)y-=d[x]-d[top[x]]+1,x=f[top[x]];
      return seq[loc[x]-y];
    }
    namespace KMP{
    int nxt[M];
    inline void cross(int x,int y,int&ret){
      int t=0,i,j,A=kth(x,d[x]-min(d[z]+len-1,d[x])),B=kth(y,d[y]-min(d[z]+len-1,d[y]));
      for(nxt[0]=j=-1,i=1;i<len;nxt[i++]=j){
        while(~j&&a[j+1]!=a[i])j=nxt[j];
        if(a[j+1]==a[i])j++;
      }
      for(j=-1;A!=z;A=f[A]){
        while(~j&&a[j+1]!=fs[A])j=nxt[j];
        if(a[j+1]==fs[A])j++;
        if(j==len-1)ret++,j=nxt[j];
      }
      while(B!=z)b[++t]=fs[B],B=f[B];
      while(t){
        while(~j&&a[j+1]!=b[t])j=nxt[j];
        if(a[j+1]==b[t])j++;
        if(j==len-1)ret++,j=nxt[j];
        t--;
      }
    }
    }
    namespace AC{
    int tot,son[M][26],f[M],q[M],g[M],nxt[M],st[M],en[M],dfn,bit[M];
    inline void addedge(int x,int y){nxt[y]=g[x];g[x]=y;}
    inline int ins0(){
      int x=0;
      for(int i=0;i<len;i++){
        if(!son[x][a[i]])son[x][a[i]]=++tot;
        x=son[x][a[i]];
      }
      return x;
    }
    inline int ins1(){
      int x=0;
      for(int i=len-1;~i;i--){
        if(!son[x][a[i]])son[x][a[i]]=++tot;
        x=son[x][a[i]];
      }
      return x;
    }
    void dfs(int x){
      st[x]=++dfn;
      for(int i=g[x];i;i=nxt[i])dfs(i);
      en[x]=dfn;
    }
    inline void add(int x,int p){for(x=st[x];x<=dfn;x+=x&-x)bit[x]+=p;}
    inline int sum(int x){int t=0;for(;x;x-=x&-x)t+=bit[x];return t;}
    inline int ask(int x){return sum(en[x])-sum(st[x]-1);}
    void make(){
      int h=1,t=0,i,j,x;f[0]=-1;
      for(i=0;i<26;i++)if(son[0][i])q[++t]=son[0][i];
      while(h<=t)for(x=q[h++],i=0;i<26;i++)
        if(son[x][i])f[son[x][i]]=son[f[x]][i],q[++t]=son[x][i];
        else son[x][i]=son[f[x]][i];
      for(i=1;i<=tot;i++)addedge(f[i],i);
      dfs(0);
    }
    }
    void dfs3(int x,int y){
      AC::add(y,1);
      for(int i=G[x];i;i=NXT[i]){
        int o=W[i];
        if(o>0)ans[o]+=AC::ask(V[i]);else ans[-o]-=AC::ask(V[i]);
      }
      for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x])dfs3(v[i],AC::son[y][w[i]]);
      AC::add(y,-1);
    }
    int main(){
      scanf("%d%d",&n,&m);
      for(i=1;i<n;i++)scanf("%d%d%s",&x,&y,a),add(x,y,a[0]-'a'),add(y,x,a[0]-'a');
      dfs(1),dfs2(1,1);
      for(ed=0,i=1;i<=m;i++){
        scanf("%d%d%s",&x,&y,a);len=strlen(a);z=lca(x,y);
        for(j=0;j<len;j++)a[j]-='a';
        KMP::cross(x,y,ans[i]);
        if(d[x]-d[z]>=len){
          j=AC::ins1();
          ADD(x,j,i);
          ADD(kth(x,d[x]-d[z]-len+1),j,-i);
        }
        if(d[y]-d[z]>=len){
          j=AC::ins0();
          ADD(y,j,i);
          ADD(kth(y,d[y]-d[z]-len+1),j,-i);
        }
      }
      AC::make();
      dfs3(1,0);
      for(i=1;i<=m;i++)printf("%d
    ",ans[i]);
      return 0;
    }
    

      

  • 相关阅读:
    sublime text 2安装及使用
    C陷阱与缺陷之语法陷阱
    上门洗车APP --- Androidclient开发 之 项目结构介绍
    编写语法分析程序
    TCP header
    boost事件处理
    TP-LINK无线路由器WR340G+ 54M支持WDS
    300M无线路由器 TL-WR842N
    python 2.7 支持dict comprehension
    100M 宽带办理
  • 原文地址:https://www.cnblogs.com/clrs97/p/5467637.html
Copyright © 2011-2022 走看看