SPOJ SUBLEX Lexicographical Substring Search - 后缀数组

题目传送门

  传送门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 }
posted @ 2018-03-25 12:39  阿波罗2003  阅读(208)  评论(0编辑  收藏  举报