bzoj4556 [Tjoi2016&Heoi2016]字符串
Description
佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为 \(n\) 的字符串 \(s\) ,和 \(m\) 个问题。佳媛姐姐必须正确回答这 \(m\) 个问题,才能打开箱子拿到礼物,升职加薪,出任 \(\mathrm{CEO}\) ,嫁给高富帅,走上人生巅峰。每个问题均有 \(a,b,c,d\) 四个参数,问你子串 \(s[a\cdots b]\) 的所有子串和 \(s[c\cdots d]\) 的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?
Input
输入的第一行有两个正整数 \(n,m\) ,分别表示字符串的长度和询问的个数。接下来一行是一个长为 \(n\) 的字符串。接下来 \(m\) 行,每行有 \(4\) 个数 \(a,b,c,d\) ,表示询问 \(s[a\cdots b]\) 的所有子串和 \(s[c\cdots d]\) 的最长公共前缀的最大值。 \(1\le n,m\le 100,000\) ,字符串中仅有小写英文字母, \(a\le b,c\le d,1\le a,b,c,d\le n\)
Output
对于每一次询问,输出答案。
Sample
Sample Input
5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4
Sample Output
1
1
2
2
2
Solution
用了一个鬼畜方法。
首先把 \(sa\) 和 \(height\) 给构造出来。然后就暴力扫 \(lcp\) ,遇到不符合长度限制的处理一下就好了。
最坏是 \(n^2\) 的,但是 \(\mathrm{bzoj}\) 的数据太弱了。
还有就是通过此题我发现我的后缀数组板子是错的(无良 \(\mathrm{liurujia}\) )!
#include<bits/stdc++.h>
using namespace std;
#define N 100001
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define drp(i, a, b) for (int i = a; i >= b; i--)
#define INF 0x7fffffff
inline int read() {
int x = 0; char ch = getchar(); while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x;
}
int sa[N], t1[N], t2[N], c[N], n, m, height[N], rnk[N];
char s[N];
void getSA(int n, int m) {
int *x = t1, *y = t2;
rep(i, 0, m - 1) c[i] = 0;
rep(i, 0, n - 1) c[x[i] = s[i]]++;
rep(i, 1, m - 1) c[i] += c[i - 1];
drp(i, n - 1, 0) sa[--c[x[i]]] = i;
for (int k = 1; k <= n; k <<= 1) {
int p = 0;
rep(i, n - k, n - 1) y[p++] = i;
rep(i, 0, n - 1) if (sa[i] >= k) y[p++] = sa[i] - k;
rep(i, 0, m - 1) c[i] = 0;
rep(i, 0, n - 1) c[x[y[i]]]++;
rep(i, 1, m - 1) c[i] += c[i - 1];
drp(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = 1, x[sa[0]] = 0;
rep(i, 1, n - 1) x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
if (p >= n) break;
m = p;
}
}
void getHeight(int n) {
int j, k = 0;
rep(i, 1, n) rnk[sa[i]] = i;
for (int i = 0; i < n; height[rnk[i++]] = k)
for (k ? k-- : 0, j = sa[rnk[i] - 1]; s[i + k] == s[j + k]; k++);
}
int main() {
scanf("%d%d%s", &n, &m, s); s[n + 1] = 0;
getSA(n + 1, 'z' + 1), getHeight(n);
while (m--) {
int a = read() - 1, b = read() - 1, c = read() - 1, d = read() - 1;
int S = rnk[c], ans = 0, mn = INF;
if (sa[S] >= a && sa[S] <= b) ans = max(ans, min(d - c + 1, b - sa[S] + 1));
drp(i, S, 2) {
if (height[i] <= ans) break;
mn = min(mn, height[i]);
if (sa[i - 1] >= a && sa[i - 1] <= b) ans = max(ans, min(min(mn, b - sa[i - 1] + 1), d - c + 1));
}
mn = INF;
rep(i, S + 1, n) {
if (height[i] <= ans) break;
mn = min(mn, height[i]);
if (sa[i] >= a && sa[i] <= b) ans = max(ans, min(min(mn, b - sa[i] + 1), d - c + 1));
}
printf("%d\n", ans);
}
return 0;
}