1. 程式人生 > >[ZJOI 2015] 諸神眷顧的幻想鄉

[ZJOI 2015] 諸神眷顧的幻想鄉

end 路徑 ack 復雜度 inline memset 統計 node else

[題目鏈接]

https://www.lydsy.com/JudgeOnline/problem.php?id=3926

[算法]

建立廣義後綴自動機

對於每個葉子節點 , 以它為根 , 依次將路徑上的子串加入自動機

最後統計本質不同的子串個數即可

時間復雜度 : O(N)

[代碼]

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
typedef long long ll;
typedef long double
ld; typedef unsigned long long ull; int n , m; int val[N]; vector< int > a[N]; struct Suffix_Automaton { int size; int father[N << 1] , child[N << 1][15] , depth[N << 1]; Suffix_Automaton() { size = 1; } inline
int new_node(int dep) { depth[++size] = dep; memset(child[size] , 0 , sizeof(child[size])); father[size] = 0; return size; } inline int extend(int last , int ch) { int np = child[last][ch];
if (np) { if (depth[np] == depth[last] + 1) return np; else { int nq = new_node(depth[last] + 1); father[nq] = father[np]; father[np] = nq; memcpy(child[nq], child[np], sizeof(child[np])); for (int p = last; child[p][ch] == np; p = father[p]) child[p][ch] = nq; return nq; } } else { np = new_node(depth[last] + 1); int p = last; for (; child[p][ch] == 0; p = father[p]) child[p][ch] = np; if (child[p][ch] == np) { father[np] = 1; return np; } int q = child[p][ch]; if (depth[p] + 1 == depth[q]) { father[np] = q; return np; } else { int nq = new_node(depth[p] + 1); father[nq] = father[q]; father[q] = father[np] = nq; memcpy(child[nq], child[q], sizeof(child[q])); for (; child[p][ch] == q; p = father[p]) child[p][ch] = nq; return np; } } } inline ll calc() { ll ans = 0; for (int i = 2; i <= size; i++) ans += depth[i] - depth[father[i]]; return ans; } } SAM; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - 0; x *= f; } inline void dfs(int u , int par , int pre) { pre = SAM.extend(pre , val[u]); for (unsigned i = 0; i < a[u].size(); i++) { int v = a[u][i]; if (v != par) dfs(v , u , pre); } } int main() { read(n); read(m); for (int i = 1; i <= n; i++) read(val[i]); for (int i = 1; i < n; i++) { int x , y; read(x); read(y); a[x].push_back(y); a[y].push_back(x); } for (int i = 1; i <= n; i++) if (a[i].size() == 1) dfs(i , 0 , 1); printf("%lld\n" , SAM.calc()); return 0; }

[ZJOI 2015] 諸神眷顧的幻想鄉