• [bzoj3926][Zjoi2015]诸神眷顾的幻想乡


    %%%

    给定一棵叶子不超过20的树,点有颜色,每两点间的路径构成一个颜色串,所有的串不同的有多少种。

    神犇们都太强了!

    首先以每个叶子为根,就得到了一个Trie树啊。

    Trie树怎么建到SAM上呢,直接以Trie上的父亲节点在SAM中的位置作为$last$,和字符串一样加入建边更新就行了。

    怎么把所有20个Trie树建到一个SAM上呢?每个Trie树直接从$init$状态开始建就行了。

    这就是广义后缀自动机?为啥对呢,,感觉就非常对2333

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100010;
    inline int read(){
        int r=0,c=getchar();
        while(!isdigit(c))c=getchar();
        while(isdigit(c))
        r=r*10+c-'0',c=getchar();
        return r;
    }
    struct SAM{
        int ch[N*20][11],fa[N*20],len[N*20];
        int sz;
        void init(){
            sz=0;fa[0]=-1;
        }
        int ins(int c,int las){
            int now=++sz;len[now]=len[las]+1;
            int p,q;
            for(p=las;~p&&!ch[p][c];p=fa[p])
            ch[p][c]=now;
            if(!~p)fa[now]=0;
            else{
                q=ch[p][c];
                if(len[q]==len[p]+1)
                    fa[now]=q;
                else{
                    int r=++sz;
                    fa[r]=fa[q];
                    for(int i=0;i<10;i++)
                    ch[r][i]=ch[q][i];
                    len[r]=len[p]+1;
                    for(;~p&&ch[p][c]==q;p=fa[p])
                    ch[p][c]=r;
                    fa[q]=fa[now]=r;
                }
            }
            return now;
        }
    }atm;
    struct Edge{
        int to,nxt;
    }e[N*2];
    int head[N],cnt=1;
    int d[N],col[N];
    void add(int u,int v){
        e[cnt]=(Edge){v,head[u]};
        head[u]=cnt++;
        e[cnt]=(Edge){u,head[v]};
        head[v]=cnt++;
        d[u]++,d[v]++;
    }
    void dfs(int u,int fa,int las){
        int now=atm.ins(col[u],las);
        for(int i=head[u];i;i=e[i].nxt)
        if(e[i].to^fa)dfs(e[i].to,u,now);
    }
    int main(){
        int n=read();read();
        for(int i=1;i<=n;i++)
        col[i]=read();
        for(int i=1;i<n;i++)
        add(read(),read());
        atm.init();
        for(int i=1;i<=n;i++)
        if(d[i]==1)dfs(i,0,0);
        long long ans=0;
        for(int i=1;i<=atm.sz;i++)
        ans+=1ll*(atm.len[i]-atm.len[atm.fa[i]]);
        cout<<ans;
    }
  • 相关阅读:
    修改其他输入法为android 默认输入法
    {php 数据类型}
    转:PHP.ini配置文件(中文)
    php导出任意mysql数据库中的表去excel文件
    php输出、写入csv
    smarty二级分类代码和模版循环例子
    笔记:使ecshop 模板中可引用 常量
    Windows下Apache2不同域名解析不同目录解决方法
    {php 数组}
    Apache中.htaccess文件功能
  • 原文地址:https://www.cnblogs.com/orzzz/p/8309168.html
Copyright © 2020-2023  润新知