题解 P3346 【[ZJOI2015]诸神眷顾的幻想乡】

· · 题解

个人认为ls的题解存在问题。不知道楼上神犇可否有空跟本蒟蒻聊聊此题正解?

这是2015年NOI集训队15人论文题,做法就是在Trie上做后缀自动机。这样的话建立的就是一个广义后缀自动机。

我来简单说下广义后缀自动机的注意点吧:

简单的实现可以每次ins完了之后,将当前指针指回SAM的根节点。

但是这必须在保证每次加入的串不会相同的情况下才可以实现。否则会导致重复加点的很多问题。

所以正确的做法是每次加入前判断当前节点在SAM中是否已经存在,再做出判断即可。

详细还请见源代码。

//                                                     /*[*/#include<stdio.h>//
//                         #include<stdlib.h>//]++++[->++[->+>++++<<]<][(c)2013]
//                        #ifndef                                           e//[o
//                       #include<string.h>//]![misaka.c,size=3808,crc=d0ec3b36][
//                      #define e                                           0x1//
//                     typedef struct{int d,b,o,P;char*q,*p;}f;int p,q,d,b,_=0//|
//                  #include __FILE__//]>>>[->+>++<<]<[-<<+>>>++<]>>+MISAKA*IMOUTO
//                #undef e//[->[-<<+<+<+>>>>]<<<<<++[->>+>>>+<<<<<]>+>+++>+++[>]]b
//             #define e(c)/**/if((_!=__LINE__?(_=__LINE__):0)){c;}//[20002,+[-.+]
//            ,O,i=0,Q=sizeof(f);static f*P;static FILE*t;static const char*o[]={//
//          "\n\40\"8oCan\40not\40open %s\n\0aaFbfeccdeaEbgecbbcda6bcedd#e(bbed$bbd",
//        "a6bgcdbbccd#ead$c%bcdea7bccde*b$eebbdda9bsdbeccdbbecdcbbcceed#eaa&bae$cbe",
//       "e&cbdd$eldbdeedbbdede)bdcdea&bbde1bedbbcc&b#ccdee&bdcdea'bbcd)e'bad(bae&bccd",
//      "e&bbda1bdcdee$bbce#b$c&bdedcd%ecdca4bhcdeebbcd#e$b#ecdcc$bccda7bbcc#e#d%c*bbda",
//     ">bad/bbda"};static int S(){return(o[p][q]);}static/**/int/**/Z=0  ;void/**/z(int//
//    l){if(/**/Z-l){Z=l;q++;if(p<b*5&&!S()){p+=b;q=0;}}}int main(int I,    /**/char**l){//
//   d=sizeof(f*);if(1<(O=_)){b=((sizeof(o)/sizeof(char*))-1)/4;q=22; p=     0;while(p<b*5){
//  /*<*/if(Z-1){d=S()>96;i=S()-(d?96:32) ;q++;if(p<b*5&&!S()){p+=b;  q=      0;}Z=1;}/*[[*/
//  while(i){_=o[0][S()-97];I=_-10?b:1;   for( ;I--;)putchar(_ );if   (!      --i||d)z(~i );}
// if(p==b*5&&O){p-=b;O--;}}return 0U;   }if(! (P=( f*)calloc /*]*/  (Q        ,I)))return 1;
// {;}for(_=p=1;p<I;p++){e(q=1);while    (q<   p&&  strcmp(  l[p     ]         ,l[(q)]))++  q;
// t=stdin;if(q<p){(void)memcpy/* "      */    (&P  [p],&P   [q     ]          ,Q);continue ;}
//if(strcmp(l[p],"-")){t=fopen(l         [     p]   ,"rb"   )                  ;if(!t ){{;}  ;
//printf(05+*o,l[p ]);return+1;                      {;}                       }}_=b= 1<<16   ;
//*&O=5;do{if(!(P[p].q=realloc   (P[p].q,(P[p].P     +=       b)+1))){return   01;}O   &=72   /
//6/*][*/;P[p].o+=d=fread(P[p]      .q       +P[     p           ].       o,  1,b,t)   ;}//
// while(d==b)      ;P [p].q[       P[       p]                  .o       ]=  012;d    =0;
// e(fclose(t        )  );P         [p]      .p                  =P[      p]  .q;if    (O)
// {for(;d<P[            p]          .o     ;d=                   q+     1)    {q=     d;
//  while(q<P[                        p].o&&P[                    p].q[q]-     10     ){
//  q++;}b=q-d;                         _=P                         [p].        d     ;
//  if(b>_){/*]b                                                                */
//   P[p].d=b;}{;                                                                }
//   #undef/*pqdz'.*/  e//                                                      ;
//   #define/*s8qdb]*/e/**/0                                                   //
//   //<<.<<.----.>.<<.>++.++<                                              .[>]
//   /*P[*/P[p].b++;continue;}}}t=                                       stdout;
//  for (p=1;p<I;p++){/**/if(P[p].b>i                               ){i=P[p].b;}}
// if  (O){for(p=0;p<i;p++){q=0;/*[*/while(I               >++q){_=P[q].p-P[q ].q;
//b=   0;if(_<P[q ].o){while(012-*P[q].p)     {putchar(*(P[q].p++));b++;}P[q]. p++;
//}   ;while (P[  q].d>b++)putchar(040);}             putchar(10);}return 0;}p   =1;
//   for(;   p<I   ;p++)fwrite(P[p] .q,P[              p].o,1,t);return 0 ;}//
//  #/*]     ]<.    [-]<[-]<[- ]<[    -]<               [-  ]<;*/elif  e    //b
// |(1        <<     ( __LINE__        /*               >>   `*//45))  |     01U
//             #                       /*               */     endif            //
#include<bits/stdc++.h>
typedef long long ll;
#define N 4000005
using namespace std;
ll ans=0;
int n,m,d[N],head[N],tot=0;
struct Edge{
    int u,v,next;
}G[N];
void addedge(int u,int v){
    G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
    G[++tot].u=v;G[tot].v=u;G[tot].next=head[v];head[v]=tot;
}
struct SuffixAutoMaton{
    int ch[N][10],fa[N],l[N];
    int rt,last,cnt;
    void init(){rt=last=++cnt;}
    int newnode(int x){l[++cnt]=x;return cnt;}
    int ins(int p,int c){
        if(ch[p][c]){
            int q=ch[p][c];
            if(l[q]==l[p]+1)last=q;
            else{
                int nq=newnode(l[p]+1);last=nq;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[nq]=fa[q];fa[q]=nq;
                for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
            }
        }
        else{
            int np=newnode(l[p]+1);last=np;
            for(;p&&(!ch[p][c]);p=fa[p])ch[p][c]=np;
            if(!p)fa[np]=rt;
            else{
                int q=ch[p][c];
                if(l[q]==l[p]+1)fa[np]=q;
                else{
                    int nq=newnode(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 last;
    }
    void calc(){
        ans=0;
        for(int i=1;i<=cnt;i++)ans+=l[i]-l[fa[i]];
    }
}sam;
int val[N];
void dfs(int u,int f,int p){
    int t=sam.ins(p,val[u]);
    for(int i=head[u];i;i=G[i].next){
        int v=G[i].v;if(v==f)continue;
        dfs(v,u,t);
    }
}
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int main(){
    n=read();m=read();sam.init();
    for(int i=1;i<=n;i++)val[i]=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read();
        addedge(u,v);d[u]++;d[v]++;
    }
    for(int i=1;i<=n;i++)if(d[i]==1)dfs(i,0,sam.rt);
    sam.calc();
    cout<<ans<<endl;
}

啊?你问我哪来的御坂妹妹?知乎上抄来的。

http://www.ioccc.org/2013/misaka/misaka.c