【题目链接】
【思路要点】
- 直接在后缀树上建边跑最长路就行了。
- 时间复杂度 O ( N a L o g ∣ S ∣ + N b L o g ∣ S ∣ + ∣ S ∣ L o g ∣ S ∣ + M ) O(N_aLog|S|+N_bLog|S|+|S|Log|S|+M) O(NaLog∣S∣+NbLog∣S∣+∣S∣Log∣S∣+M) 。
【代码】
#include<bits/stdc++.h> const int MAXN = 4e5 + 5; const int MAXM = 1e6 + 5; const int MAXLOG = 20; const long long INF = 1e18; using namespace std; template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } int val[MAXM]; bool cmp(pair <int, int> x, pair <int, int> y) { if (x.first == y.first) return val[x.second] < val[y.second]; else return x.first < y.first; } struct SuffixAutomaton { struct Node { int child[26]; int father, depth; } a[MAXN]; int root, size, last, pos[MAXN]; int father[MAXN][MAXLOG]; int newnode(int depth) { a[size].depth = depth, a[size].father = 0; memset(a[size].child, 0, sizeof(a[size].child)); return size++; } void extend(int ch, int from) { int p = last, np = newnode(a[p].depth + 1); while (a[p].child[ch] == 0) { a[p].child[ch] = np; p = a[p].father; } if (a[p].child[ch] == np) a[np].father = 0; else { int q = a[p].child[ch]; if (a[p].depth + 1 == a[q].depth) a[np].father = q; else { int nq = newnode(a[p].depth + 1); memcpy(a[nq].child, a[q].child, sizeof(a[q].child)); a[nq].father = a[q].father; a[q].father = a[np].father = nq; while (a[p].child[ch] == q) { a[p].child[ch] = nq; p = a[p].father; } } } pos[from] = last = np; } void init(char *s) { size = 0; root = last = newnode(0); int len = strlen(s + 1); for (int i = len; i >= 1; i--) extend(s[i] - 'a', i); static int cnt[MAXN]; for (int i = 1; i <= len; i++) cnt[i] = 0; for (int i = 1; i <= size - 1; i++) cnt[a[i].depth]++; for (int i = 1; i <= len; i++) cnt[i] += cnt[i - 1]; static int sa[MAXN]; for (int i = size - 1; i >= 1; i--) sa[cnt[a[i].depth]--] = i; for (int i = 1; i <= size - 1; i++) { int pos = sa[i]; memset(father[pos], 0, sizeof(father[pos])); father[pos][0] = a[pos].father; for (int p = 1; father[pos][p - 1] != 0; p++) father[pos][p] = father[father[pos][p - 1]][p - 1]; } } vector <int> b[MAXM]; vector <pair <int, int> > p[MAXN]; int sp[MAXN], tp[MAXN]; bool instack[MAXM]; long long dp[MAXM], ans; int jump(int pos, int depth) { for (int i = MAXLOG - 1; i >= 0; i--) if (a[father[pos][i]].depth >= depth) pos = father[pos][i]; return pos; } long long getdp(int pos) { if (instack[pos]) { ans = INF; return INF; } if (dp[pos] != -1) return dp[pos]; instack[pos] = true; long long res = 0; for (unsigned i = 0; i < b[pos].size(); i++) res = max(res, getdp(b[pos][i])); dp[pos] = res + val[pos]; instack[pos] = false; if (ans == INF) return INF; else return dp[pos]; } void getans() { int osize = size; for (int i = 0; i <= size - 1; i++) p[i].clear(), val[i] = 0; int n; read(n); for (int i = 1; i <= n; i++) { int x, y; read(x), read(y); int tmp = jump(pos[x], y - x + 1); sp[i] = size, val[size] = y - x + 1; p[tmp].push_back(make_pair(y - x + 1, size++)); } int m; read(m); for (int i = 1; i <= m; i++) { int x, y; read(x), read(y); int tmp = jump(pos[x], y - x + 1); tp[i] = size, val[size] = 0; p[tmp].push_back(make_pair(y - x + 1, size++)); } for (int i = 0; i <= size + n - 1; i++) { b[i].clear(); dp[i] = -1; instack[i] = false; } int q; read(q); for (int i = 1; i <= q; i++) { int x, y; read(x), read(y); b[sp[x]].push_back(tp[y]); } for (int i = 1; i <= osize - 1; i++) { sort(p[i].begin(), p[i].end(), cmp); if (p[i].empty()) b[a[i].father].push_back(i); else { for (unsigned j = 0; j < p[i].size(); j++) { if (val[p[i][j].second]) { val[size] = 0; b[size].push_back(p[i][j].second); p[i][j].second = size++; } } b[a[i].father].push_back(p[i][0].second); for (unsigned j = 1; j < p[i].size(); j++) b[p[i][j - 1].second].push_back(p[i][j].second); b[p[i].back().second].push_back(i); } } ans = 0; for (int i = 1; i <= n; i++) ans = max(ans, getdp(sp[i])); if (ans >= INF) printf("-1\n"); else cout << ans << endl; } } SAM; char s[MAXN]; int main() { int T; read(T); while (T--) { scanf("\n%s", s + 1); SAM.init(s); SAM.getans(); } return 0; }

博客介绍在后缀树上建边跑最长路的思路,给出了该方法的时间复杂度为 O(NaLog∣S∣+NbLog∣S∣+∣S∣Log∣S∣+M) ,还提供了题目链接。
469

被折叠的 条评论
为什么被折叠?



