【题目链接】
【思路要点】
- 对 S S 用后缀自动机建后缀树,并在其 序上建立主席树。
- 考虑一个询问 (T,ql,qr) ( T , q l , q r ) ,从后到前依次考虑其每一个后缀对答案的贡献,显然对于每一个后缀 i i ,存在一个长度 ,当且仅当 j>i+len j > i + l e n , T[i...j] T [ i . . . j ] 会对答案产生贡献。
- 在 S S 的后缀自动机上匹配 的每一个后缀,求出对于每一个 i i ,最大的 使得 T[i...j] T [ i . . . j ] 在 S[ql...qr] S [ q l . . . q r ] 中出现过,则 len=Max{j−i+1,lcp(i,i+1),lcp(i,i+2),...,lcp(i,|T|)} l e n = M a x { j − i + 1 , l c p ( i , i + 1 ) , l c p ( i , i + 2 ) , . . . , l c p ( i , | T | ) } ,其中 lcp(i,j) l c p ( i , j ) 表示 T[i...|T|] T [ i . . . | T | ] 和 T[j...|T|] T [ j . . . | T | ] 的 LCP L C P 。
- 再借助后缀数组求出 Max{lcp(i,i+1),lcp(i,i+2),...,lcp(i,|T|)} M a x { l c p ( i , i + 1 ) , l c p ( i , i + 2 ) , . . . , l c p ( i , | T | ) } 即可回答询问。
- 时间复杂度 O(|S|Log|S|+∑|T|∗(Log|T|+Log|S|)) O ( | S | L o g | S | + ∑ | T | ∗ ( L o g | T | + L o g | S | ) ) 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXLOG = 20;
const int MAXC = 256;
const int MAXN = 5e5 + 5;
const int MAXP = 1e6 + 5;
const int SEGP = 2e7 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
struct SegmentTree {
struct Node {
int lc, rc;
int sum;
} a[SEGP];
int n, size, root[MAXN];
void build(int &root, int l, int r) {
if (root == 0) root = ++size;
if (l == r) return;
int mid = (l + r) / 2;
build(a[root].lc, l, mid);
build(a[root].rc, mid + 1, r);
}
void init(int x) {
n = x; size = 0;
build(root[0], 1, n);
}
int modify(int root, int l, int r, int pos) {
int ans = ++size;
a[ans] = a[root];
a[ans].sum += 1;
if (l == r) return ans;
int mid = (l + r) / 2;
if (mid >= pos) a[ans].lc = modify(a[root].lc, l, mid, pos);
else a[ans].rc = modify(a[root].rc, mid + 1, r, pos);
return ans;
}
void extend(int version, int pos) {
root[version] = modify(root[version - 1], 1, n, pos);
}
int query(int rootl, int rootr, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return a[rootr].sum - a[rootl].sum;
long long ans = 0;
int mid = (l + r) / 2;
if (mid >= ql) ans += query(a[rootl].lc, a[rootr].lc, l, mid, ql, min(mid, qr));
if (mid + 1 <= qr) ans += query(a[rootl].rc, a[rootr].rc, mid + 1, r, max(mid + 1, ql), qr);
return ans;
}
int query(int l, int r, int ql, int qr) {
if (ql <= qr) return query(root[l - 1], root[r], 1, n, ql, qr);
else return 0;
}
} ST;
struct SuffixArray {
int sa[MAXN], rnk[MAXN], height[MAXN];
int Min[MAXN][MAXLOG], bit[MAXN], res[MAXN], N;
int lcp(int x, int y) {
if (x == y) return N - x + 1;
x = rnk[x], y = rnk[y];
if (x > y) swap(x, y);
int tmp = bit[y - x];
return min(Min[x][tmp], Min[y - (1 << tmp)][tmp]);
}
void init(char *a, int n) {
N = n;
static int x[MAXN], y[MAXN], cnt[MAXN], rk[MAXN];
for (int i = 1; i <= MAXC; i++)
cnt[i] = 0;
for (int i = 1; i <= n; i++)
cnt[(int) a[i]]++;
for (int i = 1; i <= MAXC; i++)
cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; i--)
sa[cnt[(int) a[i]]--] = i;
rnk[sa[1]] = 1;
for (int i = 2; i <= n; i++)
rnk[sa[i]] = rnk[sa[i - 1]] + (a[sa[i]] != a[sa[i - 1]]);
for (int k = 1; rnk[sa[n]] != n; k <<= 1) {
for (int i = 1; i <= n; i++) {
x[i] = rnk[i];
y[i] = (i + k <= n) ? rnk[i + k] : 0;
}
for (int i = 1; i <= n; i++)
cnt[i] = 0;
for (int i = 1; i <= n; i++)
cnt[y[i]]++;
for (int i = 1; i <= n; i++)
cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; i--)
rk[cnt[y[i]]--] = i;
for (int i = 1; i <= n; i++)
cnt[i] = 0;
for (int i = 1; i <= n; i++)
cnt[x[i]]++;
for (int i = 1; i <= n; i++)
cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; i--)
sa[cnt[x[rk[i]]]--] = rk[i];
rnk[sa[1]] = 1;
for (int i = 2; i <= n; i++)
rnk[sa[i]] = rnk[sa[i - 1]] + (x[sa[i]] != x[sa[i - 1]] || y[sa[i]] != y[sa[i - 1]]);
}
int now = 0; sa[n + 1] = rnk[n + 1] = 0;
for (int i = 1; i <= n; i++) {
if (now) now--;
while (a[i + now] == a[sa[rnk[i] + 1] + now]) now++;
height[rnk[i]] = now;
}
for (int i = 1; i <= n; i++)
Min[i][0] = height[i];
for (int p = 1; p < MAXLOG; p++) {
int tmp = 1 << (p - 1);
for (int i = 1, j = tmp + 1; j <= n; i++, j++)
Min[i][p] = min(Min[i][p - 1], Min[i + tmp][p - 1]);
}
for (int i = 1; i <= n; i++) {
bit[i] = bit[i - 1];
if (i >= 1 << (bit[i] + 1)) bit[i]++;
}
static set <int> st; st.clear();
for (int i = n; i >= 1; i--) {
res[i] = 0;
set <int> :: iterator tmp = st.insert(rnk[i]).first;
if (tmp != st.begin()) {
set <int> :: iterator tnp = tmp; tnp--;
chkmax(res[i], lcp(i, sa[*tnp]));
}
tmp++;
if (tmp != st.end()) chkmax(res[i], lcp(i, sa[*tmp]));
}
}
} SA;
struct SuffixAutomaton {
struct Node {
int child[26];
int father, depth;
} a[MAXP];
vector <int> b[MAXP];
char s[MAXN], t[MAXN];
int tot, list[MAXN];
int root, size, last, n;
int dfn[MAXP], rit[MAXP], mark[MAXP];
int newnode(int depth) {
a[size].depth = depth;
a[size].father = 0l;
memset(a[size].child, 0, sizeof(a[size].child));
return size++;
}
void extend(int ch, int home) {
int p = last, np = newnode(a[p].depth + 1);
while (a[p].child[ch] == 0) {
a[p].child[ch] = np;
p = a[p].father;
}
if (a[p].child[ch] == np) a[np].father = root;
else {
int q = a[p].child[ch];
if (a[p].depth + 1 == a[q].depth) a[np].father = q;
else {
int nq = newnode(a[p].depth + 1);
memcpy(a[nq].child, a[q].child, sizeof(a[q].child));
a[nq].father = a[q].father;
a[np].father = a[q].father = nq;
while (a[p].child[ch] == q) {
a[p].child[ch] = nq;
p = a[p].father;
}
}
}
last = np, mark[np] = home;
}
void dfs(int pos) {
if (mark[pos]) dfn[pos] = ++tot, list[tot] = mark[pos];
else dfn[pos] = tot + 1;
for (unsigned i = 0; i < b[pos].size(); i++)
dfs(b[pos][i]);
rit[pos] = tot;
}
void init() {
scanf("\n%s", s + 1);
n = strlen(s + 1), size = 0;
root = last = newnode(0);
for (int i = n; i >= 1; i--)
extend(s[i] - 'a', i);
for (int i = 1; i < size; i++)
b[a[i].father].push_back(i);
tot = 0, dfs(0);
ST.init(n);
for (int i = 1; i <= n; i++)
ST.extend(i, list[i]);
}
void work() {
int q; read(q);
while (q--) {
int ql, qr;
scanf("\n%s%d%d", t + 1, &ql, &qr);
int qlen = strlen(t + 1);
SA.init(t, qlen);
int len = 0, now = root;
long long ans = 0;
for (int i = qlen; i >= 1; i--) {
int ch = t[i] - 'a';
while (now != root && a[now].child[ch] == 0) {
now = a[now].father;
chkmin(len, a[now].depth);
}
if (a[now].child[ch]) {
now = a[now].child[ch];
len++;
}
while (len != 0 && ST.query(dfn[now], rit[now], ql, qr - len + 1) == 0) {
len--;
if (a[a[now].father].depth == len)
now = a[now].father;
}
ans += qlen - i + 1 - max(len, SA.res[i]);
}
writeln(ans);
}
}
} SAM;
int main() {
SAM.init();
SAM.work();
return 0;
}