# luogu P4482 [BJWC2018] Border 的四种求法 - 后缀数组

区间border。

照着金策讲稿做。

### Code

  1 /**
2  * luogu
3  * Problem#P4482
4  * Accepted
5  * Time: 8264ms
6  * Memory: 37924k
7  */
8 #include <bits/stdc++.h>
9 using namespace std;
10 typedef bool boolean;
11
12 template <typename T>
13 void pfill(T* pst, const T* ped, T val) {
14     for ( ; pst != ped; *(pst++) = val);
15 }
16
17 const int N = 2e5 + 5;
18 const int bzmax = 19;
19 const signed int inf = (signed) (~0u >> 2);
20
21 typedef class SparseTable {
22     public:
23         int n;
24         int *ar;
25         int log2[N];
26         int f[N][bzmax];
27
28         SparseTable() {    }
29
30         void init(int n, int* ar) {
31             this->n = n;
32             this->ar = ar;
33             log2[1] = 0;
34             for (int i = 2; i <= n; i++)
35                 log2[i] = log2[i >> 1] + 1;
36             for (int i = 0; i < n; i++)
37                 f[i][0] = ar[i];
38             for (int j = 1; j < bzmax; j++)
39                 for (int i = 0; i + (1 << j) - 1 < n; i++)
40                     f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
41         }
42
43         int query(int l, int r) {
44             int d = log2[r - l + 1];
45             return min(f[l][d], f[r - (1 << d) + 1][d]);
46         }
47 } SparseTable;
48
49 typedef class Pair3 {
50     public:
51         int x, y, id;
52
53         Pair3() {    }
54         Pair3(int x, int y, int id):x(x), y(y), id(id) {    }
55 } Pair3;
56
57 typedef class SuffixArray {
58     protected:
59         Pair3 T1[N], T2[N];
60         int cnt[N];
61
62     public:
63         int n;
64         char *str;
65         int sa[N], rk[N], hei[N];
66         SparseTable st;
67
68         void set(int n, char* str) {
69             this->n = n;
70             this->str = str;
71             memset(sa, 0, sizeof(sa));
72             memset(rk, 0, sizeof(rk));
73             memset(hei, 0, sizeof(hei));
74         }
75
76         void radix_sort(Pair3* x, Pair3* y) {
77             int m = max(n, 256);
78             memset(cnt, 0, sizeof(int) * m);
79             for (int i = 0; i < n; i++)
80                 cnt[x[i].y]++;
81             for (int i = 1; i < m; i++)
82                 cnt[i] += cnt[i - 1];
83             for (int i = 0; i < n; i++)
84                 y[--cnt[x[i].y]] = x[i];
85
86             memset(cnt, 0, sizeof(int) * m);
87             for (int i = 0; i < n; i++)
88                 cnt[y[i].x]++;
89             for (int i = 1; i < m; i++)
90                 cnt[i] += cnt[i - 1];
91             for (int i = n - 1; ~i; i--)
92                 x[--cnt[y[i].x]] = y[i];
93         }
94
95         void build() {
96             for (int i = 0; i < n; i++)
97                 rk[i] = str[i];
98             for (int k = 1; k <= n; k <<= 1) {
99                 for (int i = 0; i + k < n; i++)
100                     T1[i] = Pair3(rk[i], rk[i + k], i);
101                 for (int i = n - k; i < n; i++)
102                     T1[i] = Pair3(rk[i], 0, i);
104                 int diff = 1;
105                 rk[T1[0].id] = 1;
106                 for (int i = 1; i < n; i++)
107                     rk[T1[i].id] = (T1[i].x == T1[i - 1].x && T1[i].y == T1[i - 1].y) ? (diff) : (++diff);
108                 if (diff == n)
109                     break;
110             }
111             for (int i = 0; i < n; i++)
112                 sa[--rk[i]] = i;
113         }
114
115         void get_height() {
116             for (int i = 0, j, k = 0; i < n; i++, (k) ? (k--) : (0)) {
117                 if (rk[i]) {
118                     j = sa[rk[i] - 1];
119                     while (i + k < n && j + k < n && str[i + k] == str[j + k])    k++;
120                     hei[rk[i]] = k;
121                 }
122             }
123         }
124
125         void init_st() {
126             st.init(n, hei);
127         }
128
129         int lcp(int x1, int x2) {
130             if (x1 == x2)
131                 return n - x1 + 1;
132             x1 = rk[x1], x2 = rk[x2];
133             if (x1 > x2)
134                 swap(x1, x2);
135             return st.query(x1 + 1, x2);
136         }
137
138         int compare(int l1, int r1, int l2, int r2) {
139             int len_lcp = lcp(l1, l2);
140             int len1 = r1 - l1 + 1, len2= r2 - l2 + 1;
141             if (len_lcp >= len1 && len_lcp >= len2)
142                 return 0;
143             if (len_lcp < len1 && len_lcp < len2)
144                 return (str[l1 + len_lcp] < str[l2 + len_lcp]) ? (-1) : (1);
145             return (len_lcp >= len1) ? (-1) : (1);
146         }
147
148         int query(int u, int v) {    // u, v -> sa
149             if (u == v)
150                 return n - sa[u];
151             return st.query(u + 1, v);
152         }
153
154         const int& operator [] (int p) {
155             return sa[p];
156         }
157
158         const int& operator () (int p) {
159             return hei[p];
160         }
161 } SuffixArray;
162
163 namespace IPM { // Internal Pattern Matching
164
165 typedef class MatchingData {
166     public:
167         int a0, a1;
168         int amount;
169
170         MatchingData() : amount(0) {    }
171         explicit MatchingData(int a0) : a0(a0), a1(a0), amount(1) {    }
172         MatchingData(int a0, int a1) : a0(a0), a1(a1), amount(1 + (a0 != a1)) {    }
173         MatchingData(int a0, int a1, int amount) : a0(a0), a1(a1), amount(amount) {    }
174         MatchingData(int* a, int amount) : amount(amount) {
175             if (amount == 0)
176                 return;
177             if (amount == 1)
178                 a0 = a1 = a[0];
179             else if (amount >= 2) {
180                 a0 = a[0], a1 = a[1];
181                 int d = a1 - a0;
182                 for (int i = 2; i < amount; i++)
183                     if (a[i] - a[i - 1] != d)
184                         assert(false);
185             }
186         }
187
188         boolean included(int x) {
189             if (!amount)
190                 return false;
191             boolean aflag = (x == a0 || x == a1);
192             if (amount <= 2 || aflag)
193                 return aflag;
194             x -= a0;
195             int d = a1 - a0;
196             return (!(x % d) && (x / d >= 0 && x / d < amount));
197         }
198
199         int indexOf(int x) {
200             if (!included(x))
201                 return -1;
202             return (x - a0) / (a1 - a0);
203         }
204
205         int last() {
206             return value(amount - 1);
207         }
208
209         int value(int n) {
210             return a0 + (a1 - a0) * n;
211         }
212
213         int dif() {
214             return a1 - a0;
215         }
216
217         MatchingData operator - () {
218             return MatchingData(-a0, -a1, amount);
219         }
220
221         MatchingData operator + (int d) {
222             return MatchingData(a0 + d, a1 + d, amount);
223         }
224
225         MatchingData operator - (int d) {
226             return MatchingData(a0 - d, a1 - d, amount);
227         }
228
229         MatchingData operator ~ () {
230             if (amount <= 1)
231                 return *this;
232             int _a0 = value(amount - 1);
233             int _a1 = value(amount - 2);
234             return MatchingData(_a0, _a1, amount);
235         }
236
237         MatchingData operator & (MatchingData b) {
238             static int tmp[6];
239             if (!amount || !b.amount)
240                 return MatchingData();
241             if (amount < 3) {
242                 int tp = 0;
243                 for (int i = 0, x = a0, d = a1 - a0; i < amount; i++, x += d) {
244                     if (b.included(x)) {
245                         tmp[tp++] = x;
246                     }
247                 }
248                 return MatchingData(tmp, tp);
249             }
250             if (b.amount < 3) {
251                 int tp = 0;
252                 for (int i = 0, x = b.a0, d = b.a1 - b.a0; i < b.amount; i++, x += d) {
253                     if (included(x)) {
254                         tmp[tp++] = x;
255                     }
256                 }
257                 return MatchingData(tmp, tp);
258             }
259             int d = a1 - a0;
260             assert(d == b.a1 - b.a0);
261             int l = indexOf(b.a0), r = l + b.amount;
262             if (l == -1)
263                 return MatchingData();
264             l = max(l, 0);
265             r = min(amount, r);
266             if (l >= r)
267                 return MatchingData();
268             return MatchingData(value(l), value(l + 1), r - l);
269         }
270 } MatchingData;
271
272 int n;
273 char* str;
274 //int *log2;
275 SuffixArray sa;
276 int f[bzmax][N];
277
278 inline void init(char* str, int _n) {
279 //    log2 = new int[(n + 1)];
280 //    log2[0] = -1;
281 //    for (int i = 1; i <= n; i++)
282 //        log2[i] = log2[i >> 1] + 1;
283     n = _n;
284     sa.set(n, str);
285     sa.build();
286     sa.get_height();
287     sa.init_st();
288     for (int k = 0; (1 << k) <= n; k++) {
289         int* F = f[k], len = (1 << k);
290         for (int i = 0; i + len <= n; i++)
291             F[i] = i;
292         sort(F, F + (n - len) + 1, [&] (const int& x, const int& y) {
293             int rt = sa.compare(x, x + len - 1, y, y + len - 1);
294             if (!rt)
295                 return x < y;
296             return rt == -1;
297         });        // it can be replace by radix sort
298     }
299 }
300
301 pair<int, int> getRange(int s, int k) {
302     int len = 1 << k, l = 0, r = n - len, mid;
303     int* F = f[k], L, R;
304     while (l <= r) {
305         mid = (l + r) >> 1;
306         if (sa.compare(s, s + len - 1, F[mid], F[mid] + len - 1) == 1)
307             l = mid + 1;
308         else
309             r = mid - 1;
310     }
311     L = r + 1;
312     l = 0, r = n - len;
313     while (l <= r) {
314         mid = (l + r) >> 1;
315         if (sa.compare(s, s + len - 1, F[mid], F[mid] + len - 1) >= 0)
316             l = mid + 1;
317         else
318             r = mid - 1;
319     }
320     R = l - 1;
321     return pair<int, int>(L, R);
322 }
323
324 int succ(int s, int k, int i, int L, int R) {    // pos >= i
325     int len = 1 << k, l = 0, r = n - len;
326     int mid;
327     int *F = f[k];
328     if (L > R)
329         return inf;
330     l = L, r = R;
331     while (l <= r) {
332         mid = (l + r) >> 1;
333         if (F[mid] >= i)
334             r = mid - 1;
335         else
336             l = mid + 1;
337     }
338     if (r == R)
339         return inf;
340     return F[r + 1];
341 }
342
343 int pred(int s, int k, int i) { //<= i
344     int len = 1 << k, l = 0, r = n - len;
345     int L, R, mid;
346     int *F = f[k];
347     while (l <= r) {
348         mid = (l + r) >> 1;
349         if (sa.compare(s, s + len - 1, F[mid], F[mid] + len - 1) == 1)
350             l = mid + 1;
351         else
352             r = mid - 1;
353     }
354     L = r + 1;
355     l = 0, r = n - len;
356     while (l <= r) {
357         mid = (l + r) >> 1;
358         if (sa.compare(s, s + len - 1, F[mid], F[mid] + len - 1) >= 0)
359             l = mid + 1;
360         else
361             r = mid - 1;
362     }
363     R = l - 1;
364     if (L > R)
365         return -1;
366     l = L, r = R;
367     while (l <= r) {
368         mid = (l + r) >> 1;
369         if (F[mid] <= i)
370             l = mid + 1;
371         else
372             r = mid - 1;
373     }
374     if (l == L)
375         return -1;
376     return F[l - 1];
377 }
378
379 // rt - lt + 1 = 2 ^ k
380 MatchingData query(int ls, int rs, int lt, int k) {
381     int len = 1 << k;
382     pair<int, int> range = getRange(lt, k);
383     int a0 = succ(lt, k, ls, range.first, range.second);
384     if (a0 + len - 1 > rs)
385         return MatchingData();
386     int a1 = succ(lt, k, a0 + 1, range.first, range.second);
387     if (a1 + len - 1 > rs)
388         return MatchingData(a0);
389     int an = pred(lt, k, rs - len + 1);
390     assert(an >= ls);
391     MatchingData rt (a0, a1);
392     rt.amount = N;
393     rt.amount = rt.indexOf(an) + 1;
394     return rt;
395 }
396
397 }
398
399 using IPM :: MatchingData;
400
401 int n, m;
402 char str[N];
403
404 inline void init() {
405     scanf("%s", str);
406     n = strlen(str);
407     IPM :: init(str, n);
408 }
409
410 int query(int l, int r) {
411     int t = 0, half_len = (r - l + 2) >> 1;
412     while ((1 << t) < half_len)
413         t++;
414     for (int i = t; ~i; i--) {
415         int len = min(r - l, 1 << (i + 1)), hlen = (1 << i);
416         MatchingData md_l = IPM :: query(l, l + len - 1, r - hlen + 1, i);
417         MatchingData md_r = IPM :: query(r - len + 1, r, l, i);
418         md_l = md_l - l + hlen;
419         md_r = -(~md_r) + (r + 1);
420         md_l = md_l & md_r;
421         if (md_l.amount)
422             return md_l.last();
423     }
424     return (str[l] == str[r] && l < r);
425 }
426
427 inline void solve() {
428     scanf("%d", &m);
429     int l, r;
430     while (m--) {
431         scanf("%d%d", &l, &r);
432         printf("%d\n", query(--l, --r));
433     }
434 }
435
436 int main() {
437 //    freopen("border.in", "r", stdin);
438 //    freopen("border.out", "w", stdout);
439     init();
440     solve();
441     return 0;
442 }

posted @ 2019-01-07 12:01 阿波罗2003 阅读(...) 评论(...) 编辑 收藏