[ZJOI2015]诸神眷顾的幻想乡
OJ题号:
BZOJ3926、洛谷3346
题目大意:
给定一棵带权树,定义两个路径是不同的当且仅当两个路径上的权值构成的串不同,求本质不同的路径个数。
思路:
广义后缀自动机。
从每个叶子结点开始DFS,并依次加入到SAM中,对于每个加入的结点,last状态是其父亲节点所在的状态,其余插入过程与普通SAM类似。
每个叶子结点的last状态为root。
询问过程与普通SAM完全相同。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<cstring> 5 inline int getint() { 6 char ch; 7 while(!isdigit(ch=getchar())); 8 int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int V=100001; 13 std::vector<int> e[V]; 14 int deg[V]; 15 inline void add_edge(const int u,const int v) { 16 e[u].push_back(v); 17 deg[u]++; 18 } 19 int col[V]; 20 class GeneralSuffixAutomaton { 21 private: 22 static const int SIGMA_SIZE=10,MAX_STATE=V<<5; 23 struct State { 24 int link,go[SIGMA_SIZE],len; 25 }; 26 State s[MAX_STATE]; 27 int sz,newState(const int l) { 28 sz++; 29 s[sz].len=l; 30 return sz; 31 } 32 int extend(int p,const int w) { 33 int new_p=newState(s[p].len+1); 34 while(p&&!s[p].go[w]) { 35 s[p].go[w]=new_p; 36 p=s[p].link; 37 } 38 if(!p) { 39 s[new_p].link=root; 40 } else { 41 int q=s[p].go[w]; 42 if(s[q].len==s[p].len+1) { 43 s[new_p].link=q; 44 } else { 45 int new_q=newState(s[p].len+1); 46 memcpy(s[new_q].go,s[q].go,sizeof s[q].go); 47 s[new_q].link=s[q].link; 48 s[q].link=s[new_p].link=new_q; 49 while(p&&s[p].go[w]==q) { 50 s[p].go[w]=new_q; 51 p=s[p].link; 52 } 53 } 54 } 55 return new_p; 56 } 57 public: 58 int root; 59 GeneralSuffixAutomaton() { 60 root=newState(0); 61 } 62 void build(const int x,const int par,const int lastptr) { 63 int p=extend(lastptr,col[x]); 64 for(unsigned i=0;i<e[x].size();i++) { 65 int &y=e[x][i]; 66 if(y==par) continue; 67 build(y,x,p); 68 } 69 } 70 long long query() { 71 long long ret=0; 72 for(int i=1;i<=sz;i++) { 73 if(s[i].link) { 74 ret+=s[i].len-s[s[i].link].len; 75 } 76 } 77 return ret; 78 } 79 }; 80 GeneralSuffixAutomaton sam; 81 int main() { 82 int n=getint(),m=getint(); 83 for(int i=1;i<=n;i++) col[i]=getint(); 84 for(int i=1;i<n;i++) { 85 int u=getint(),v=getint(); 86 add_edge(u,v); 87 add_edge(v,u); 88 } 89 for(int i=1;i<=n;i++) { 90 if(deg[i]==1) { 91 sam.build(i,0,sam.root); 92 } 93 } 94 printf("%lld\n",sam.query()); 95 return 0; 96 }