【BZOJ】3926: [Zjoi2015]诸神眷顾的幻想乡
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3926
广义后缀自动机...
久仰公之大名啊...
太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过$20$个。
这就是说叶子节点的个数不超过$20$个,我们知道树上的每一条路径一定对应了一个:以某一个叶子节点为根的tire树的后缀的前缀(也就是子串),我们知道SAM是可以统计不同子串的个数的即:${\sum _{i=1}^{n} (len[i]-len[fa[i]])}$
考虑如何把这20棵tire构成一个后缀自动机,我们在只有一个串的时候$np$就是直接指向前一个字符的位置,因为我们现在是树结构,所以$np$指向的应该是该点在$trie$树中父节点的位置,其他的就和普通的$SAM$一样,为了找到节点的父亲,$DFS$找即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 using namespace std; 9 #define maxn 1000010 10 #define llg long long 11 #define SIZE 11 12 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 13 llg n,m,last=1,root=1,du[maxn],v[maxn]; 14 15 vector<llg>a[maxn]; 16 17 struct SAM 18 { 19 struct 20 { 21 llg len,f,ch[SIZE]; 22 void init(){len=0,f=0,memset(ch,0,sizeof(ch));} 23 }e[maxn*2]; 24 25 llg insert(llg p,llg c) 26 { 27 llg np=++last; e[np].init(); 28 e[np].len=e[p].len+1; 29 for (;p && !e[p].ch[c];p=e[p].f) e[p].ch[c]=np; 30 if (!p) e[np].f=root; 31 else 32 { 33 llg q=e[p].ch[c]; 34 if (e[q].len==e[p].len+1) e[np].f=q; 35 else 36 { 37 llg nq=++last; 38 e[nq].init(); 39 e[nq]=e[q]; 40 e[nq].len=e[p].len+1; 41 e[q].f=e[np].f=nq; 42 for (;p && e[p].ch[c]==q;p=e[p].f) e[p].ch[c]=nq; 43 } 44 } 45 return np; 46 } 47 }sam; 48 49 void init() 50 { 51 llg x,y; 52 cin>>n>>m; 53 for (llg i=1;i<=n;i++) scanf("%lld",&v[i]); 54 for (llg i=1;i<n;i++) 55 { 56 scanf("%lld%lld",&x,&y); 57 a[x].push_back(y),a[y].push_back(x); 58 du[x]++,du[y]++; 59 } 60 } 61 62 void dfs(llg x,llg fa,llg p) 63 { 64 llg t=sam.insert(p,v[x]),w=a[x].size(); 65 for (llg i=0;i<w;i++) 66 if (a[x][i]!=fa) 67 dfs(a[x][i],x,t); 68 } 69 70 int main() 71 { 72 yyj("god"); 73 init(); 74 for (llg i=1;i<=n;i++) if (du[i]==1) dfs(i,0,1); 75 llg ans=0; 76 for (llg i=1;i<=last;i++) ans+=sam.e[i].len-sam.e[sam.e[i].f].len; 77 cout<<ans; 78 return 0; 79 }
本文作者:xrdog
作者博客:http://www.cnblogs.com/Dragon-Light/
转载请注明出处,侵权必究,保留最终解释权!