[TJOI2016 & HEOI2016] 字符串
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=4556
[算法]
不难发现 , 对于每个询问
ans = max{ min{b - i + 1 , lcp(i , c) } (a <= i <= b)
不妨二分答案mid , 那么问题就转化为求 max{ lcp(i , c) } (a <= i <= b - mid + 1)
而我们知道 , 所有lcp(i , j) <= k的i是连续的一段区间
可以再次通过二分求出这个区间
问题又转化为判断[a , b - mid + 1]中是否有rank值在区间[L , R]中的数
构建出后缀数组 , 主席树维护rank值即可
时间复杂度 : O(NlogN ^ 2)
[代码]
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; const int MAXLOG = 17; typedef long long ll; typedef long double ld; typedef unsigned long long ull; #define rint register int int n , m; int rk[N] , rt[N] , sa[N] , cnt[N] , height[N] , lg[N]; int val[N][MAXLOG]; char s[N]; struct Presitent_Segment_Tree { int sz; int lc[N * 40] , rc[N * 40] , cnt[N * 40]; Presitent_Segment_Tree() { sz = 0; } inline void build(int &now , int l , int r) { now = ++sz; if (l == r) return; int mid = (l + r) >> 1; build(lc[now] , l , mid); build(rc[now] , mid + 1 , r); } inline void modify(int &now , int old , int l , int r , int x , int value) { now = ++sz; lc[now] = lc[old] , rc[now] = rc[old]; cnt[now] = cnt[old] + value; if (l == r) return; int mid = (l + r) >> 1; if (mid >= x) modify(lc[now] , lc[old] , l , mid , x , value); else modify(rc[now] , rc[old] , mid + 1 , r , x , value); } inline bool query(int rt1 , int rt2 , int l , int r , int ql , int qr) { if (ql > qr || cnt[rt1] - cnt[rt2] == 0) return false; if (l == ql && r == qr) return (cnt[rt1] - cnt[rt2] > 0); int mid = (l + r) >> 1; if (mid >= qr) return query(lc[rt1] , lc[rt2] , l , mid , ql , qr); else if (mid + 1 <= ql) return query(rc[rt1] , rc[rt2] , mid + 1 , r , ql , qr); else return query(lc[rt1] , lc[rt2] , l , mid , ql , mid) | query(rc[rt1] , rc[rt2] , mid + 1 , r , mid + 1 , qr); } } PST; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void build_sa() { static int x[N] , y[N]; memset(cnt , 0 , sizeof(cnt)); for (rint i = 1; i <= n; i++) ++cnt[(int)s[i]]; for (rint i = 1; i <= 256; i++) cnt[i] += cnt[i - 1]; for (rint i = n; i >= 1; i--) sa[cnt[(int)s[i]]--] = i; rk[sa[1]] = 1; for (rint i = 2; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]); for (rint k = 1; rk[sa[n]] != n; k <<= 1) { for (rint i = 1; i <= n; i++) x[i] = rk[i] , y[i] = (i + k <= n) ? rk[i + k] : 0; memset(cnt , 0 , sizeof(cnt)); for (rint i = 1; i <= n; i++) ++cnt[y[i]]; for (rint i = 1; i <= n; i++) cnt[i] += cnt[i - 1]; for (rint i = n; i >= 1; i--) rk[cnt[y[i]]--] = i; memset(cnt , 0 , sizeof(cnt)); for (rint i = 1; i <= n; i++) ++cnt[x[i]]; for (rint i = 1; i <= n; i++) cnt[i] += cnt[i - 1]; for (rint i = n; i >= 1; i--) sa[cnt[x[rk[i]]]--] = rk[i]; rk[sa[1]] = 1; for (rint i = 1; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (x[sa[i]] != x[sa[i - 1]] || y[sa[i]] != y[sa[i - 1]]); } } inline void get_height() { int k = 0; for (rint i = 1; i <= n; i++) { if (k) --k; int j = sa[rk[i] - 1]; while (s[i + k] == s[j + k]) ++k; height[rk[i]] = k; } } inline void rmq_init() { for (rint i = 1; i <= n; i++) val[i][0] = height[i]; for (rint j = 1; (1 << j) <= n; j++) { for (rint i = 1; i + (1 << j) - 1 <= n; i++) { val[i][j] = min(val[i][j - 1] , val[i + (1 << (j - 1))][j - 1]); } } } inline int query(int x , int y) { if (x > y) return 0; int k = lg[y - x + 1]; return min(val[x][k] , val[y - (1 << k) + 1][k]); } int main() { scanf("%d%d" , &n , &m); scanf("%s" , s + 1); build_sa(); get_height(); rmq_init(); PST.build(rt[0] , 1 , n); for (rint i = 1; i <= n; i++) PST.modify(rt[i] , rt[i - 1] , 1 , n , rk[i] , 1); for (rint i = 1; i <= n; i++) lg[i] = (double)(log(i) / log(2.0)); while (m--) { int a , b , c , d; read(a); read(b); read(c); read(d); int l = 1 , r = min(d - c + 1 , b - a + 1) , ans = 0; while (l <= r) { int mid = (l + r) >> 1; int ll = 1 , rr = rk[c] - 1 , L = rk[c] , R = rk[c]; while (ll <= rr) { int md = (ll + rr) >> 1; if (query(md + 1 , rk[c]) >= mid) { L = md; rr = md - 1; } else ll = md + 1; } ll = rk[c] + 1 , rr = n , R = rk[c]; while (ll <= rr) { int md = (ll + rr) >> 1; if (query(rk[c] + 1 , md) >= mid) { R = md; ll = md + 1; } else rr = md - 1; } if (PST.query(rt[b - mid + 1] , rt[a - 1] , 1 , n , L , R)) { l = mid + 1; ans = mid; } else r = mid - 1; } printf("%d\n" , ans); } return 0; }