[ZJOI2015] 諸神眷顧的幻想鄉 - 廣義字尾自動機,樹
阿新 • • 發佈:2020-07-13
Description
給定一棵葉子結點數量 \(\le 20\) 的樹,在樹上任選一條路,問有多少種顏色序列不同的選擇。
Solution
一條路徑一定屬於以某個葉子為根的樹上所有的直鏈的集合
於是我們把以每個葉子為根的樹 DFS 一遍,當作一個 Trie 插入廣義字尾自動機即可
#include <bits/stdc++.h> #define int long long using namespace std; const int N = 2000005; int n,c,a[N],t1,t2,t3,vis[N],pos[N],d[N]; vector <int> g[N]; struct SAM { int len[N], ch[N][10], fa[N], ind, last; SAM() { ind = last = 1; } inline int extend(int id) { if(ch[last][id] && len[last]+1==len[ch[last][id]]) return ch[last][id]; //! int cur = (++ ind), p, tmp, flag = 0; //! len[cur] = len[last] + 1; for (p = last; p && !ch[p][id]; p = fa[p]) ch[p][id] = cur; if (!p) fa[cur] = 1; else { int q = ch[p][id]; if (len[q] == len[p] + 1) fa[cur] = q; else { if(p==last) flag=1; //! tmp = (++ ind); len[tmp] = len[p] + 1; for(int i=0;i<10;i++) ch[tmp][i] = ch[q][i]; fa[tmp] = fa[q]; for (; p && ch[p][id] == q; p = fa[p]) ch[p][id] = tmp; fa[cur] = fa[q] = tmp; } } last = cur; return flag ? tmp : cur;//! } void dfs(int p) { vis[p]=1; for(int q:g[p]) { if(!vis[q]) { last=pos[p]; pos[q]=extend(a[q]); dfs(q); } } } void ins(int rt) { memset(vis,0,sizeof vis); memset(pos,0,sizeof pos); last=1; pos[rt]=extend(a[rt]); dfs(rt); } int getans() { int ans=0; for(int i=1;i<=ind;i++) ans+=len[i]-len[fa[i]]; return ans; } } sam; signed main() { ios::sync_with_stdio(false); cin>>n>>c; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<n;i++) { cin>>t1>>t2; g[t1].push_back(t2); g[t2].push_back(t1); d[t1]++; d[t2]++; } for(int i=1;i<=n;i++) { if(d[i]==1) { sam.ins(i); } } cout<<sam.getans()<<endl; }