• BZOJ 3926 ZJOI2015 诸神眷顾的幻想乡 广义后缀自动机


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3926

    题意概述:给出一棵N个结点的树,树上最多有20个叶子,每个点有颜色,编号0~9。求树上不同的颜色路径(由一个点到另一个点的路径上的点的颜色按顺序排列而成)数量。N<=100000.

    当你发现只有20个叶子的时候你就很开心了因为你发现可以乱搞了。

    使用秘技——广义后缀自动机来节省空间(实际上广义后缀自动机是对一棵trie做的自动机,解决多母串问题)。可以直接把原树分别以20个结点为根看成20棵trie,弄到SAM里面去。在树的分支处就让这个结点来充当所有儿子的last,仔细一想你发现SAM的性质并没有改变,并且trie的不同分支之间没有影响(说白了广义后缀自动机就是一个能够识别trie中某个结点开始的所有后缀的自动机)。

    统计答案的时候直接用每个状态的MAX减去其parent的MAX就可以得到答案。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<queue>
     8 #include<set>
     9 #include<map>
    10 #include<vector>
    11 #include<cctype>
    12 using namespace std;
    13 const int MAXN=100005;
    14 typedef long long LL;
    15 
    16 int N,C,c[MAXN];
    17 struct edge{ int to,next; }E[MAXN<<1];
    18 int first[MAXN],np;
    19 struct SAM{
    20     static const int maxn=4000005;
    21     static const int sigma_sz=10;
    22     int sz,to[maxn][sigma_sz],mx[maxn],pa[maxn];
    23     SAM(){ sz=1; }
    24     int newnode(){
    25         memset(to[++sz],0,sizeof(to[sz]));
    26         mx[sz]=pa[sz]=0;
    27         return sz;
    28     }
    29     int extend(int w,int p){
    30         int np=newnode();
    31         mx[np]=mx[p]+1;
    32         while(p&&!to[p][w]) to[p][w]=np,p=pa[p];
    33         if(!p) pa[np]=1;
    34         else{
    35             int q=to[p][w];
    36             if(mx[q]==mx[p]+1) pa[np]=q;
    37             else{
    38                 int nq=newnode(); mx[nq]=mx[p]+1;
    39                 memcpy(to[nq],to[q],sizeof(to[nq]));
    40                 pa[nq]=pa[q];
    41                 pa[q]=pa[np]=nq;
    42                 while(p&&to[p][w]==q) to[p][w]=nq,p=pa[p];
    43             }
    44         }
    45         return np;
    46     }
    47     LL calc(){
    48         LL re=0;
    49         for(int i=2;i<=sz;i++) re+=mx[i]-mx[pa[i]];
    50         return re;
    51     }
    52 }sam;
    53 
    54 void _scanf(int &x)
    55 {
    56     x=0;
    57     char ch=getchar();
    58     while(ch<'0'||ch>'9') ch=getchar();
    59     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    60 }
    61 void add_edge(int u,int v)
    62 {
    63     E[++np]=(edge){v,first[u]};
    64     first[u]=np;
    65 }
    66 void data_in()
    67 {
    68     _scanf(N);_scanf(C);
    69     for(int i=1;i<=N;i++) _scanf(c[i]);
    70     int x,y;
    71     for(int i=1;i<N;i++){
    72         _scanf(x);_scanf(y);
    73         add_edge(x,y); add_edge(y,x);
    74     }
    75 }
    76 void DFS(int i,int f,int p)
    77 {
    78     int pp=sam.extend(c[i],p);
    79     for(int p=first[i];p;p=E[p].next){
    80         int j=E[p].to;
    81         if(j==f) continue;
    82         DFS(j,i,pp);
    83     }
    84 }
    85 void work()
    86 {
    87     for(int i=1;i<=N;i++)
    88         if(!E[first[i]].next) DFS(i,0,1);
    89     cout<<sam.calc()<<'
    ';
    90 }
    91 int main()
    92 {
    93     data_in();
    94     work();
    95     return 0;
    96 }
  • 相关阅读:
    javascript的alert的使用
    UIGestureRecognizer对图像进行缩放、移动、旋转操作
    对开源库使用 AutoCAD 文件格式
    计算机图形学常用算法
    KMP字符串模式匹配详解
    C++面试题String函数实现
    c++虚函数解析
    c++内存分配
    win32编程入门
    C++中Int转换成String
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8529624.html
Copyright © 2020-2023  润新知