Description
给出一个字符串(S)和若干次询问
每次询问给出一个字符串(T)和(l,r),询问(T)中有多少个本质不同的子串在(S[l...r])中未出现过
Solution
首先我们考虑当(l=1)且(r=n)的情况,那么我们考虑对于(T)的每一前缀求出一个最长的后缀满足这个后缀在(S)中出现过,然后记这个后缀的长度为(len)。那么如果不算本质不同的话,答案就是(frac{m imes (m-1)}{2}-sum len),但是题目要求本质不同,所以我们考虑对(T)也建出一个后缀自动机,然后每次就在(T)的后缀自动机上面每个节点维护一个(mx_i)表示(i)这个节点上所代表的字符串中所有长度(le mx_i)的串都在(S)中出现过,那么这样我们每次匹配到了一个(T)的一个前缀,我们就可以在代表这个前缀的节点上面打上一个标记,最后做一遍(DFS)合并所有标记就好了,答案就是(sum max(0,mx_i-len_{fa_i}))
然后考虑(l,r)任意的情况,这样我们就需要将匹配的条件再进行限制,就是新限制匹配的这个点的(right)集合中一定存在点在([l,r])这个区间中,具体实现就是我们考虑线段树合并得出(right)集合,然后线段树上面的节点表示的就是在这个区间中(right)集合最大的位置,那么我们直接在这个点上面的线段树询问一下([1,r])的最大值并且将(len=min(len, ml - l + 1)),(ml)表示最大值,这样限制匹配就好了
Code
//Created Time:2020年04月10日 星期五 20时27分30秒
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1000006
using namespace std;
inline void ckmax(int &x, int y){x = x > y ? x : y;}
int n;
char s[N], t[N];
//{{{SMT
struct SMT{
int cnt;
int ls[N * 50], rs[N * 50], val[N * 50];
void update(int &pos, int l, int r, int p){
if(!pos) pos = ++cnt; ckmax(val[pos], p);
if(l == r) return ;
int mid = (l + r) >> 1;
if(mid >= p) update(ls[pos], l, mid, p);
else update(rs[pos], mid + 1, r, p);
return ;
}
int query(int &pos, int l, int r, int nl, int nr){
if(!pos) return 0;
if(l >= nl && r <= nr) return val[pos];
int mid = (l + r) >> 1, res = 0;
if(mid >= nl) ckmax(res, query(ls[pos], l, mid, nl, nr));
if(mid < nr) ckmax(res, query(rs[pos], mid + 1, r, nl, nr));
return res;
}
int merge(int x, int y){
if(!x || !y) return x | y;
int pos = ++cnt; val[pos] = max(val[x], val[y]);
ls[pos] = merge(ls[x], ls[y]);
rs[pos] = merge(rs[x], rs[y]);
return pos;
}
}T;
//}}}
int rt[N];
struct SAM1{
int cnt, lst;
int ch[N][26], fa[N], len[N], d[N], id[N];
void ins(int x, int pos){
int p = lst, np = ++cnt; lst = np; len[np] = len[p] + 1;
T.update(rt[np], 1, n, pos);
for(; p && !ch[p][x]; p = fa[p]) ch[p][x] = np;
if(!p) fa[np] = 1;
else{
int q = ch[p][x];
if(len[q] == len[p] + 1) fa[np] = q;
else{
int nq = ++cnt; memcpy(ch[nq], ch[q], sizeof ch[nq]);
len[nq] = len[p] + 1; fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for(; p && ch[p][x] == q; p = fa[p]) ch[p][x] = nq;
}
}
return ;
}
void get(){
for(int i = 2; i <= cnt; ++i) ++d[len[i]];
for(int i = 1; i <= cnt; ++i) d[i] += d[i - 1];
for(int i = cnt; i >= 2; --i) id[d[len[i]]--] = i;
for(int i = cnt - 1; i; --i){
int u = id[i], f = fa[u];
rt[f] = T.merge(rt[f], rt[u]);
}
return ;
}
void find(int &p, int &nl, int x, int l, int r){
while(p){
int v = ch[p][x], ml = 0;
if(v) ml = T.query(rt[v], 1, n, 1, r);
if(ml >= l && ml - l + 1 > len[fa[p]])
return nl = min(nl + 1, ml - l + 1), p = v, void();
p = fa[p], nl = len[p];
} p = 1, nl = 0;
return ;
}
}sam1;
struct SAM2{
int cnt, lst;
int ch[N][26], fa[N], len[N], d[N], id[N], ans[N];
void init(){
for(int i = 1; i <= cnt; ++i){
memset(ch[i], 0, sizeof ch[i]);
fa[i] = len[i] = ans[i] = d[i] = 0;
}
cnt = lst = 1;
return ;
}
int ins(int x){
int p = lst, np = ++cnt; lst = np; len[np] = len[p] + 1;
for(; p && !ch[p][x]; p = fa[p]) ch[p][x] = np;
if(!p) fa[np] = 1;
else{
int q = ch[p][x];
if(len[q] == len[p] + 1) fa[np] = q;
else{
int nq = ++cnt; memcpy(ch[nq], ch[q], sizeof ch[nq]);
len[nq] = len[p] + 1; fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for(; p && ch[p][x] == q; p = fa[p]) ch[p][x] = nq;
}
}
return np;
}
long long calc(){
long long res = 0;
for(int i = 2; i <= cnt; ++i) ++d[len[i]], res += len[i] - len[fa[i]];
for(int i = 1; i <= cnt; ++i) d[i] += d[i - 1];
for(int i = cnt; i >= 2; --i) id[d[len[i]]--] = i;
for(int i = cnt - 1; i; --i){
int u = id[i], f = fa[u];
res -= max(0, ans[u] - len[f]), ckmax(ans[f], min(len[f], ans[u]));
}
return res;
}
}sam2;
int pos[N];
int main(){
scanf("%s", s + 1); n = strlen(s + 1); sam1.cnt = sam1.lst = 1;
for(int i = 1; i <= n; ++i) sam1.ins(s[i] - 'a', i);
sam1.get(); int T; cin >> T;
while(T--){
sam2.init(); scanf("%s", t + 1);
int m = strlen(t + 1), l, r;
scanf("%d%d", &l, &r);
for(int i = 1; i <= m; ++i)
pos[i] = sam2.ins(t[i] - 'a');
int now = 1, len = 0;
for(int i = 1; i <= m; ++i){
sam1.find(now, len, t[i] - 'a', l, r);
ckmax(sam2.ans[pos[i]], len);
}
printf("%lld
", sam2.calc());
}
return 0;
}