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;
}
posted @ 2018-03-23 15:21  aziint  阅读(181)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.