1. 程式人生 > >[XSY 1551] 往事 廣義後綴數組

[XSY 1551] 往事 廣義後綴數組

++ emp algo build math read cto space put

題意

  給定一棵 n 個點的樹, 每條邊上有字符 c .

  定義 s[i] 為從 i 到根的所有字符組成的字符串.

  求 $\max_{1 \le u < v \le n} [ LCP(s[u], s[v]) + LCS(s[u], s[v]) ]$ .

  n <= 200000 .

實現1  n log^2 n 廣義後綴數組 + 啟發式合並

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cctype>
  5 #include <cmath>
  6
#include <algorithm> 7 #include <vector> 8 #include <set> 9 using namespace std; 10 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 11 #define P(i, a, b) for (register int i = (a); i >= (b); i--) 12 #define LL unsigned long long 13 14 namespace Input {
15 const int S = 2000000; 16 char s[S], *h = s+S, *t = h; 17 inline char getchr(void) { if (h == t) fread(s, 1, S, stdin), h = s; return *h++; } 18 inline int rd(void) { 19 int f = 1; char c = getchr(); for (; !isdigit(c); c = getchr()) if (c == -) f = -1; 20 int x = 0
; for (; isdigit(c); c = getchr()) x = x*10+c-0; return x*f; 21 } 22 } 23 using Input::rd; 24 25 const int N = 200005; 26 // remember to change back 27 const int U = 20; 28 const int M = 307; 29 30 int n; 31 vector<int> g[N]; 32 33 int u, dep[N]; 34 int par[U][N]; 35 LL p[N], Hash[U][N]; 36 37 void Build(void) { 38 n = rd(); 39 u = (int)log2(n); 40 p[0] = 1; 41 F(i, 1, n) p[i] = p[i-1] * M; 42 43 F(i, 2, n) { 44 int f = rd(), c = rd() + 1; // guaranteed that (empty = 0) < (0 + 1) 45 g[f].push_back(i); 46 dep[i] = dep[f] + 1; 47 par[0][i] = f; 48 Hash[0][i] = c; 49 } 50 51 F(i, 1, u) F(j, 1, n) { 52 par[i][j] = par[i-1][par[i-1][j]]; 53 Hash[i][j] = Hash[i-1][j] * p[1 << (i-1)] + Hash[i-1][par[i-1][j]]; 54 } 55 } 56 57 int sa[N], rk[N], h[N]; 58 int Log2[N], Min[U][N]; 59 60 inline int cmp(int x, int y) { 61 P(i, u, 0) 62 if (dep[x] >= (1<<i) && dep[y] >= (1<<i) && Hash[i][x] == Hash[i][y]) 63 x = par[i][x], y = par[i][y]; 64 return Hash[0][x] < Hash[0][y]; 65 } 66 inline int Get(int x, int y) { 67 int Len = 0; 68 P(i, u, 0) 69 if (dep[x] >= (1<<i) && dep[y] >= (1<<i) && Hash[i][x] == Hash[i][y]) 70 x = par[i][x], y = par[i][y], Len += (1<<i); 71 return Len; 72 } 73 inline int LCP(int x, int y) { 74 // It‘s guaranteed that [x != y] 75 if (x > y) swap(x, y); 76 x++; 77 int c = Log2[y - x + 1]; 78 return min(Min[c][y], Min[c][x + (1 << c) - 1]); 79 } 80 void Prework(void) { 81 F(i, 1, n) sa[i] = i; 82 sort(sa+1, sa+n+1, cmp); 83 F(i, 1, n) rk[sa[i]] = i; 84 85 F(i, 2, n) 86 h[i] = Get(sa[i-1], sa[i]); 87 88 F(i, 1, n) 89 Log2[i] = (int)log2(i); 90 91 F(i, 1, n) Min[0][i] = h[i]; 92 F(i, 1, u) F(j, 1, n) 93 Min[i][j] = min(Min[i-1][j], Min[i-1][max(1, j - (1 << (i-1)))]); 94 } 95 96 set<int> s[N]; 97 int Max; 98 99 inline void Merge(int x, int y) { 100 if (s[x].size() < s[y].size()) swap(s[x], s[y]); 101 for (set<int>::iterator it = s[y].begin(); it != s[y].end(); it++) { 102 // [ Insert ] and [ Find LCP with *it ] 103 s[x].insert(*it); 104 set<int>::iterator it2 = s[x].find(*it); 105 if (it2 != s[x].begin()) { 106 it2--; 107 Max = max(Max, dep[x] + LCP(*it2, *it)); 108 it2++; 109 } 110 if (++it2 != s[x].end()) 111 Max = max(Max, dep[x] + LCP(*it2, *it)); 112 } 113 s[y].clear(); // release the non-use recollection 114 } 115 void Calc(int x) { 116 s[x].insert(rk[x]); 117 for (vector<int>::iterator it = g[x].begin(); it != g[x].end(); it++) { 118 Calc(*it); 119 Merge(x, *it); 120 } 121 } 122 123 int main(void) { 124 #ifndef ONLINE_JUDGE 125 freopen("recollection.in", "r", stdin); 126 #endif 127 128 Build(); 129 Prework(); 130 Calc(1); printf("%d\n", Max); 131 132 return 0; 133 }

[XSY 1551] 往事 廣義後綴數組