luogu P4482 [BJWC2018] 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); 103 radix_sort(T1, T2); 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 }