1. 程式人生 > >SPOJ SUBLEX Lexicographical Substring Search - 後綴數組

SPOJ SUBLEX Lexicographical Substring Search - 後綴數組

har .net query round order tro OS style 直接

題目傳送門

  傳送門I

  傳送門II

題目大意

  給定一個字符串,多次詢問它的第$k$大本質不同的子串,輸出它。

  考慮後綴Trie。依次考慮每個後綴新增的本質不同的子串個數,顯然,它是$n - sa[i] - height[i]$。

  求出$height$數組後,求一求本質不同的子串個數的前綴和,可以對每個詢問二分。

  這裏可以直接離線,$O(n + m)$掃一掃就好了。

Code

  1 /**
  2  * SPOJ
  3  * Problem#SUBLEX
  4  * Accepted
  5  * Time: 30ms
  6  * Memory: 19456k
7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 typedef class Pair3 { 13 public: 14 int x, y, id; 15 }Pair3; 16 17 typedef class Query { 18 public: 19 int k, s, t, id; 20 21 boolean operator < (Query b) const
{ 22 return k < b.k; 23 } 24 }Query; 25 26 const int N = 1e5 + 5, M = 505; 27 28 int n, m; 29 char str[N], bs[N]; 30 int rk[N << 1], sa[N], hei[N], cnt[N]; 31 Pair3 ps[N], buf[N]; 32 Query qs[M]; 33 34 inline void init() { 35 scanf("%s", str + 1
); 36 n = strlen(str + 1); 37 scanf("%d", &m); 38 for (int i = 1; i <= m; i++) 39 scanf("%d", &qs[i].k), qs[i].id = i; 40 } 41 42 inline void radix_sort(Pair3* x, Pair3* y) { 43 int m = ((n > 256) ? (n) : (256)); 44 memset(cnt, 0, sizeof(int) * (m + 1)); 45 for (int i = 1; i <= n; i++) cnt[x[i].y]++; 46 for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1]; 47 for (int i = 1; i <= n; i++) y[cnt[x[i].y]--] = x[i]; 48 memset(cnt, 0, sizeof(int) * (m + 1)); 49 for (int i = 1; i <= n; i++) cnt[y[i].x]++; 50 for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1]; 51 for (int i = n; i; i--) x[cnt[y[i].x]--] = y[i]; 52 } 53 54 inline void build_sa() { 55 for (int i = 1; i <= n; i++) 56 rk[i] = str[i]; 57 for (int k = 1, dif = 0; k <= n; k <<= 1, dif = 0) { 58 for (int i = 1; i <= n; i++) 59 ps[i].x = rk[i], ps[i].y = rk[i + k], ps[i].id = i; 60 radix_sort(ps, buf); 61 rk[ps[1].id] = ++dif; 62 for (int i = 2; i <= n; i++) 63 rk[ps[i].id] = (dif += (ps[i].x != ps[i - 1].x || ps[i].y != ps[i - 1].y)); 64 if (dif == n) 65 break; 66 } 67 for (int i = 1; i <= n; i++) 68 sa[rk[i]] = i; 69 } 70 71 inline void get_height() { 72 for (int i = 1, j, k = 0; i <= n; i++) { 73 if (k) k--; 74 if (rk[i] > 1) { 75 for (j = sa[rk[i] - 1]; i + k <= n && j + k <= n && str[i + k] == str[j + k]; k++); 76 hei[rk[i]] = k; 77 } else 78 hei[1] = 0; 79 } 80 } 81 82 inline void solve() { 83 build_sa(); 84 get_height(); 85 // for (int i = 1; i <= n; i++) 86 // cerr << hei[i] << " "; 87 // cerr << endl; 88 sort(qs + 1, qs + m + 1); 89 long long cur = 0; 90 for (int i = 1, nq = 1, delta; i <= n && nq <= m; i++) { 91 delta = n - sa[i] + 1 - hei[i]; 92 if (cur + delta < qs[nq].k) 93 cur += delta; 94 else { 95 qs[nq].s = sa[i], qs[nq].t = sa[i] + hei[i] + (qs[nq].k - cur); 96 nq++, i--; 97 } 98 } 99 for (int i = 1; i <= m; i++) 100 while (qs[i].id != i) 101 swap(qs[qs[i].id], qs[i]); 102 for (int i = 1; i <= m; i++) { 103 int len = qs[i].t - qs[i].s; 104 memcpy(bs, str + qs[i].s , len); 105 bs[len] = 0; 106 puts(bs); 107 } 108 } 109 110 int main() { 111 init(); 112 solve(); 113 return 0; 114 }

SPOJ SUBLEX Lexicographical Substring Search - 後綴數組