题解:
考虑离线然后一个一个添加字符,这样问题就转化成了字符串T在字符串S[1, i]中出现了多少次,直接对S串建SAM,然后询问只需要拓扑排序然后求字符串T走过去的子树大小即可,但是这样很明显过于暴力了。因此我们可以利用LCT来帮助我们快速求出子树大小以达到 O ( n l o g n ) O(nlogn) O(nlogn)
代码:
/*
* @Author : Nightmare
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 100005
#define M 100005
#define mod 1000000007
#define inf 0x3f3f3f3f
struct LCT{
static const int maxn = 4e5 + 5;
int sum[maxn], tag[maxn], son[maxn][2], fa[maxn], st[maxn];
bool isroot(int x){ return son[fa[x]][0] != x && son[fa[x]][1] != x; }
bool isright(int x){ return son[fa[x]][1] == x; }
void add(int a, int b){ if(a) sum[a] += b, tag[a] += b; }
void pushdown(int x){
int lson = son[x][0], rson = son[x][1];
if(tag[x]) add(lson, tag[x]), add(rson, tag[x]), tag[x] = 0;
}
void rotate(int x){
int y = fa[x], z = fa[y], dy = isright(y), dx = isright(x);
fa[x] = z;
if(!isroot(y)) son[z][dy] = x;
fa[son[x][dx ^ 1]] = y; son[y][dx] = son[x][dx ^ 1];
fa[y] = x; son[x][dx ^ 1] = y;
}
void splay(int x){
int top = 0; st[++ top] = x;
for(int i = x ; !isroot(i) ; i = fa[i]) st[++ top] = fa[i];
while(top) pushdown(st[top --]);
while(!isroot(x)){
int y = fa[x], z = fa[y];
if(!isroot(y)) rotate((son[y][0] == x) ^ (son[z][0] == y) ? x : y);
rotate(x);
}
}
void access(int x){
for(int y = 0 ; x ; x = fa[x]) splay(x), son[x][1] = y, y = x;
}
void link(int x, int y){
fa[x] = y;
access(y);
splay(y);
add(y, sum[x]);
}
void cut(int x){
access(x);
splay(x);
add(son[x][0], -sum[x]);
fa[son[x][0]] = 0;
son[x][0] = 0;
}
}lct;
struct SAM {
static const int maxn = 2e5 + 5;
int nxt[maxn][26], fa[maxn], len[maxn], last = 1, tot = 1;
inline void init() {
for (int i = 0; i <= tot; i++) fa[i] = len[i] = 0, memset(nxt[i], 0, sizeof(nxt[i]));
last = tot = 1;
}
inline void insert(int x) {
int p = last, np = ++tot;
last = np, len[np] = len[p] + 1;
lct.sum[np] = 1;
for (; p && !nxt[p][x]; p = fa[p]) nxt[p][x] = np;
if (!p) fa[np] = 1, lct.link(np, 1);
else {
int q = nxt[p][x];
if (len[p] + 1 == len[q]) fa[np] = q, lct.link(np, q);
else {
int nq = ++tot; len[nq] = len[p] + 1;
memcpy(nxt[nq], nxt[q], sizeof(nxt[q]));
fa[nq] = fa[q];
lct.link(nq, fa[q]);
fa[q] = fa[np] = nq;
lct.cut(q);
lct.link(q, nq);
lct.link(np, nq);
for (; nxt[p][x] == q; p = fa[p]) nxt[p][x] = nq;
}
}
}
inline int query(string str){
int rt = 1, n = str.length();
for(int i = 0 ; i < n ; i ++){
if(!nxt[rt][str[i] - 'a']) return 0;
rt = nxt[rt][str[i] - 'a'];
}
lct.splay(rt);
return lct.sum[rt];
}
}sam;
char str[N]; string ss[N];
vector<PII> que[N];
int n, Q, ans[N];
void solve(){
cin >> (str + 1); n = strlen(str + 1);
cin >> Q;
for(int i = 1, l, r ; i <= Q ; i ++){
cin >> l >> r >> ss[i];
if(ss[i].length() > r - l + 1) continue;
que[r].emplace_back(i, 1);
que[l + ss[i].length() - 2].emplace_back(i, -1);
}
sam.init();
for(int i = 1 ; i <= n ; i ++){
sam.insert(str[i] - 'a');
for(auto &q : que[i]) ans[q.first] += q.second * sam.query(ss[q.first]);
}
for(int i = 1 ; i <= Q ; i ++) cout << ans[i] << endl;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("D:\\in.txt", "r", stdin);
#endif
solve();
#ifndef ONLINE_JUDGE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}