zoukankan      html  css  js  c++  java
  • BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡(后缀自动机)

    传送门

    解题思路

      因为叶节点不超过(20)个,所以可以枚举这些叶节点,并把这些节点当做根扫整棵树。可以证明所有的子串一定可以被便利到,然后可以对这些串建广义后缀自动机。(dfs)的时候要记录一下上一个节点后缀自动机中的标号,从这个标号开始建后缀自动机。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
     
    using namespace std;
    const int N=100005;
    const int M=N*20;
    typedef long long LL;
     
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return f?x:-x;
    }
     
    struct SAM{
        int fa[M<<1],ch[M<<1][11],l[M<<1],cnt;
        inline int insert(int c,int pre){
            int p=pre,np=++cnt;l[np]=l[p]+1;
            for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
            if(!p) fa[np]=1;
            else {
                int q=ch[p][c];
                if(l[q]==l[p]+1) fa[np]=q;
                else {
                    int nq=++cnt;l[nq]=l[p]+1;
                    memcpy(ch[nq],ch[q],sizeof(ch[q]));
                    fa[nq]=fa[q];fa[q]=fa[np]=nq;
                    for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 
                }
            }
            return np;
        }
    }sam;
     
    int n,c,w[N],head[N],tot,to[N<<1],nxt[N<<1],deg[N];
    LL ans;
     
    inline void add(int bg,int ed){
        to[++tot]=ed,nxt[tot]=head[bg],head[bg]=tot;
    }
     
    void dfs(int x,int lst,int F){
        int now=sam.insert(w[x],lst);
        for(int i=head[x];i;i=nxt[i]){
            int u=to[i];if(u==F) continue;
            dfs(u,now,x);
        }
    }
     
    int main(){
        sam.cnt=1;n=rd(),c=rd(); int x,y;
        for(int i=1;i<=n;i++) w[i]=rd();
        for(int i=1;i<n;i++){
            x=rd(),y=rd();
            add(x,y),add(y,x);
            deg[x]++;deg[y]++;
        }
        for(int i=1;i<=n;i++)
            if(deg[i]==1) dfs(i,1,0);
        for(int i=1;i<=sam.cnt;i++) ans+=(sam.l[i]-sam.l[sam.fa[i]]);
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    MySQL学习笔记
    FileInputStream
    Java 多个if 和多个else if 的区别
    Flume 聚合
    Flume SinkProcessor
    Flume ChannelSelector (包括自定义flume拦截器)
    Flume 案例演示
    為政第二
    各种版本 WordCount
    學而第一
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10290195.html
Copyright © 2011-2022 走看看