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

    3926: [Zjoi2015]诸神眷顾的幻想乡

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 843  Solved: 510
    [Submit][Status][Discuss]

    Description

     幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日。 

    粉丝们非常热情,自发组织表演了一系列节目给幽香看。幽香当然也非常高兴啦。 
    这时幽香发现了一件非常有趣的事情,太阳花田有n块空地。在过去,幽香为了方便,在这n块空地之间修建了n-1条边将它们连通起来。也就是说,这n块空地形成了一个树的结构。 
    有n个粉丝们来到了太阳花田上。为了表达对幽香生日的祝贺,他们选择了c中颜色的衣服,每种颜色恰好可以用一个0到c-1之间的整数来表示。并且每个人都站在一个空地上,每个空地上也只有一个人。这样整个太阳花田就花花绿绿了。幽香看到了,感觉也非常开心。 
    粉丝们策划的一个节目是这样的,选中两个粉丝A和B(A和B可以相同),然后A所在的空地到B所在的空地的路径上的粉丝依次跳起来(包括端 点),幽香就能看到一个长度为A到B之间路径上的所有粉丝的数目(包括A和B)的颜色序列。一开始大家打算让人一两个粉丝(注意:A,B和B,A是不同 的,他们形成的序列刚好相反,比如红绿蓝和蓝绿红)都来一次,但是有人指出这样可能会出现一些一模一样的颜色序列,会导致审美疲劳。 
    于是他们想要问题,在这个树上,一共有多少可能的不同的颜色序列(子串)幽香可以看到呢? 
    太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过20个。 

    Input

     第一行两个正整数n,c。表示空地数量和颜色数量。 

    第二行有n个0到c-1之间,由空格隔开的整数,依次表示第i块空地上的粉丝的衣服颜色。(这里我们按照节点标号从小到大的顺序依次给出每块空地上粉丝的衣服颜色)。 
    接下来n-1行,每行两个正整数u,v,表示有一条连接空地u和空地v的边。 

    Output

     一行,输出一个整数,表示答案。 

    Sample Input

    7 3
    0 2 1 2 1 0 0
    1 2
    3 4
    3 5
    4 6
    5 7
    2 5

    Sample Output

    30

    HINT

    对于所有数据,1<=n<=100000, 1<=c<=10。 

    对于15%的数据,n<=2000。 
    另有5%的数据,所有空地都至多与两个空地相邻。 
    另有5%的数据,除一块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻。 
    另有5%的数据,除某两块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻。
      
      知道要从每个叶子节点建trie树再合并,我就会做了。
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 using namespace std;
     5 const int maxn=100010;
     6 const int maxm=2000010;
     7 long long ans;
     8 bool vis[maxm];
     9 int n,sumc,cntE,c[maxn];
    10 int fir[maxn],nxt[maxn<<1],to[maxn<<1];
    11 void addedge(int a,int b){
    12     nxt[++cntE]=fir[a];
    13     fir[a]=cntE;
    14     to[cntE]=b;
    15 }
    16 int st[maxm],topst;
    17 int CH[maxm][11],pos[maxm];
    18 int fa[maxm],ch[maxm][11],len[maxm];
    19 struct SAM{
    20     int cnt,last;
    21     SAM(){
    22         cnt=last=1;
    23     }
    24     int Insert(int c){
    25         int p=last,np=last=++cnt;len[np]=len[p]+1;
    26         while(p&&!ch[p][c])ch[p][c]=np,p=fa[p];
    27         if(!p)fa[np]=1;
    28         else{
    29             int q=ch[p][c];
    30             if(len[p]+1==len[q])
    31                 fa[np]=q;
    32             else{
    33                 int nq=++cnt;len[nq]=len[p]+1;
    34                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
    35                 fa[nq]=fa[q];fa[q]=fa[np]=nq;
    36                 while(ch[p][c]==q)ch[p][c]=nq,p=fa[p];
    37             }    
    38         }
    39         ans+=len[last]-len[fa[last]];
    40         return last;
    41     }
    42 }sam;
    43 struct Trie{
    44     int cnt,rt;
    45     Trie(){
    46         rt=cnt=1;
    47         pos[rt]=1;
    48     }
    49     void Insert(int &x,int p){
    50         vis[p]=true;
    51         if(!x)x=++cnt;
    52         for(int i=fir[p];i;i=nxt[i])
    53             if(!vis[to[i]])
    54                 Insert(CH[x][c[to[i]]],to[i]);
    55     }
    56     void Construct(int x){
    57         for(int i=0;i<sumc;i++)
    58             if(CH[x][i]){
    59                 sam.last=pos[x];
    60                 pos[CH[x][i]]=sam.Insert(i);
    61             }
    62         for(int i=0;i<sumc;i++)
    63             if(CH[x][i])
    64                 Construct(CH[x][i]);
    65     }
    66 }trie;
    67 int main(){
    68 #ifndef ONLINE_JUDGE
    69     freopen("zjoi15_substring.in","r",stdin);
    70     freopen("zjoi15_substring.out","w",stdout);
    71 #endif
    72     scanf("%d%d",&n,&sumc);
    73     for(int i=1;i<=n;i++)
    74         scanf("%d",&c[i]); 
    75     for(int i=1,a,b;i<n;i++){
    76         scanf("%d%d",&a,&b);
    77         addedge(a,b);
    78         addedge(b,a);
    79     }    
    80     for(int x=1,tot=0;x<=n;tot=0,x++){
    81         for(int i=fir[x];i;i=nxt[i])tot+=1;
    82         if(tot==1)st[++topst]=x;
    83     }
    84     while(topst){
    85         memset(vis,0,sizeof(vis));
    86         trie.Insert(CH[trie.rt][c[st[topst]]],st[topst]);
    87         topst-=1;
    88     }
    89     trie.Construct(trie.rt);
    90     printf("%lld
    ",ans);
    91     return 0;    
    92 }
    尽最大的努力,做最好的自己!
  • 相关阅读:
    在linux下Ant的环境配置
    在linux下Java的环境配置
    CSS列表逆序
    HTML元素基础学习
    第一天---HTML基础学习
    排球计分程序
    罗辑思维:怎样成为一个高手 观后感
    十八周个人作业
    本周个人作业
    个人作业
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5595066.html
Copyright © 2011-2022 走看看