Problem:
String in String
Problem
文字列
S
と
Q
個のクエリが与えられる。
i
番目のクエリ(0 ≤
i
≤
Q
-1)には閉区間[
l
i
,
r
i
]と文字列
M
i
が与えられる。
S
の
l
i
文字目から
r
i
文字目までの部分文字列の中に文字列
M
i
はいくつ存在するか出力せよ。
Input
入力は以下の形式で与えられる。
S
Q
l
0
r
0
M
0
l
1
r
1
M
1
.
.
.
l
Q−1
r
Q−1
M
Q−1
1行目に文字列
S
とクエリの数
Q
が空白区切りで与えられる。
続く
Q
行に整数
l
i
,
r
i
,
M
i
が空白区切りで与えられる。
Constraints
1 ≤|
S
| ≤ 100000
1 ≤
Q
≤ 100000
1 ≤ |
M
i
| ≤ 100000 (0 ≤
i
≤
Q
-1)
0 ≤
l
i
≤
r
i
< |
S
| (0 ≤
i
≤
Q
-1)
文字はすべて英小文字である
文字列
M
の合計文字数は2000000を越えない
Output
出力は
Q
行からなる。各クエリに対する答えを順番に1行に出力せよ。
Sample Input 1
rupcrupc 5
0 3 rupc
0 7 rupc
2 7 ru
2 7 pc
1 5 u
Sample Output 1
1
2
1
2
2
Sample Input 2
abatagaadbura 8
0 6 a
6 12 a
0 6 aa
0 3 a
3 5 a
5 9 a
1 8 b
1 12 b
Sample Output 2
4
3
0
2
1
2
1
2
Sample Input 3
aaaaaaaaaa 5
0 9 aaa
0 9 aa
5 9 aaaa
2 8 aa
1 2 a
Sample Output 3
8
9
2
6
2

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Node {
    int next[26];
    int fail;
    vector<int> out;
    Node() : fail(0) {
        for(int i=0;i<26;i++) next[i]=-1;
    }
};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    string S; int Q;
    cin >> S >> Q;
    struct Query {int l, r; string m; int id;};
    vector<Query> qs(Q);
    vector<string> p;
    p.reserve(Q);
    for(auto &q: qs){cin>>q.l>>q.r>>q.m; p.push_back(q.m);}
    sort(p.begin(), p.end());
    p.erase(unique(p.begin(), p.end()), p.end());
    int P = p.size();
    vector<Node> trie(1);
    for(int i=0;i<P;i++){
        int node=0;
        for(char c:p[i]){
            if(trie[node].next[c-'a']==-1){
                trie[node].next[c-'a'] = trie.size();
                trie.emplace_back();
            }
            node = trie[node].next[c-'a'];
        }
        trie[node].out.push_back(i);
    }
    queue<int> q;
    for(int c=0;c<26;c++) {
        if(trie[0].next[c]!=-1){
            trie[trie[0].next[c]].fail=0;
            q.push(trie[0].next[c]);
        }
        else trie[0].next[c]=0;
    }
    while(!q.empty()){
        int current = q.front(); q.pop();
        for(int c=0;c<26;c++){
            if(trie[current].next[c]!=-1){
                int child = trie[current].next[c];
                int f = trie[current].fail;
                while(trie[f].next[c]==-1 && f!=0) f = trie[f].fail;
                if(trie[f].next[c]!=-1) trie[child].fail = trie[f].next[c];
                else trie[child].fail = 0;
                for(auto &x: trie[trie[child].fail].out) trie[child].out.push_back(x);
                q.push(child);
            }
            else trie[current].next[c] = trie[trie[current].fail].next[c];
        }
    }
    vector<vector<int>> o(P);
    int node=0;
    for(int i=0;i<S.size();i++){
        int c=S[i]-'a';
        node = trie[node].next[c];
        for(auto &x: trie[node].out){
            int pos = i - (int)p[x].size() +1;
            if(pos >=0) o[x].push_back(pos);
        }
    }
    for(auto &q: qs){
        q.id = lower_bound(p.begin(), p.end(), q.m) - p.begin();
    }
    for(auto &q: qs){
        int a=q.l, m=p[q.id].size(), b=q.r - m +1;
        if(b < a || m ==0){cout<< "0\n"; continue;}
        cout<< upper_bound(o[q.id].begin(), o[q.id].end(), b) - lower_bound(o[q.id].begin(), o[q.id].end(), a) << "\n";
    }
}
accuracy: 1
time_ms: 300
memory_kb: 285384
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct N { 
    int n[26], f; 
    vector<int> o; 
    N() : f(-1) { 
        for(int i = 0; i < 26; i++) n[i] = -1; 
    }
};
struct Qr { int l, r; string m; int id; };

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    string S; 
    int Qc; 
    cin >> S >> Qc;
    
    vector<Qr> qs(Qc); 
    vector<string> p;
    for(auto &q: qs){
        cin >> q.l >> q.r >> q.m; 
        p.push_back(q.m);
    }
    
    sort(p.begin(), p.end());
    p.erase(unique(p.begin(), p.end()), p.end());
    
    int P = p.size(); 
    vector<N> t(1);
    
    for(int i = 0; i < P; i++){
        int node = 0; 
        for(char c : p[i]){
            if(t[node].n[c - 'a'] == -1){
                t[node].n[c - 'a'] = t.size(); 
                t.emplace_back();
            }
            node = t[node].n[c - 'a'];
        }
        t[node].o.push_back(i);
    }
    
    queue<int> q; 
    for(int c = 0; c < 26; c++) {
        if(t[0].n[c] != -1){
            t[t[0].n[c]].f = 0; 
            q.push(t[0].n[c]);
        }
        else {
            t[0].n[c] = 0;
        }
    }
    
    while(!q.empty()){
        int cur = q.front(); 
        q.pop();
        for(int c = 0; c < 26; c++){
            if(t[cur].n[c] != -1){
                int child = t[cur].n[c];
                int f = t[cur].f;
                while(t[f].n[c] == -1 && f != 0) f = t[f].f;
                if(t[f].n[c] != -1) 
                    t[child].f = t[f].n[c];
                else 
                    t[child].f = 0;
                
                for(auto &x: t[t[child].f].o) 
                    t[child].o.push_back(x);
                
                q.push(child);
            }
            else {
                t[cur].n[c] = t[t[cur].f].n[c];
            }
        }
    }
    
    vector<vector<int>> o(P);
    int node = 0;
    for(int i = 0; i < S.size(); i++){
        int c = S[i] - 'a';
        node = t[node].n[c];
        for(auto &x: t[node].o){
            int pos = i - (int)p[x].size() + 1;
            if(pos >= 0) 
                o[x].push_back(pos);
        }
    }
    
    for(auto &q: qs){
        q.id = lower_bound(p.begin(), p.end(), q.m) - p.begin();
    }
    
    for(auto &q: qs){
        int a = q.l; 
        int m = p[q.id].size(); 
        int b = q.r - m + 1;
        if(b < a || m == 0){
            cout << "0\n"; 
            continue;
        }
        cout << upper_bound(o[q.id].begin(), o[q.id].end(), b) - lower_bound(o[q.id].begin(), o[q.id].end(), a) << "\n";
    }
}
accuracy: 1
time_ms: 300
memory_kb: 285908
final_rank: 11

code_snippet: #include<bits/stdc++.h>
#define pb push_back
#define ll long long
using namespace std;
struct suffix_array {
	vector<int> sa, rk, lcp;
	//sa:后缀排序;rk:后缀名次;lcp:最长公共前缀
	int len; string s;
	void getsa() {
		sa.clear(); rk.clear(); sa.resize(len + 1, 0); rk.resize(len + 1, 0); sa[0] = len;
		for(int i = 1; i <= len; i++) sa[i] = i - 1;
		sort(sa.begin() + 1, sa.end(), [&](int a, int b) {return s[a] < s[b];});
		for(int i = 1; i <= len; i++) {
			int a = sa[i - 1], b = sa[i];
			if(i > 1 && s[a] == s[b]) rk[b] = rk[a];
			else rk[b] = i;
		}
		for(int siz = 1; siz <= len; siz *= 2) {
			vector<int> lsa(sa), lrk(rk), cnt(len + 1);
			for(int i = 0; i <= len; i++) cnt[i] = i;
			for(auto t : lsa) {
				int T = t - siz;
				if(T >= 0) sa[cnt[lrk[T]]++] = T;
			}
			for(int i = 1; i <= len; i++) {
				int a = sa[i - 1], b = sa[i];
				if(lrk[a] == lrk[b] && lrk[a + siz] == lrk[b + siz]) rk[b] = rk[a];
				else rk[b] = i;
			}
		}
	}
	void getlcp() {
		lcp.clear(); lcp.resize(len, 0); int h = 0;
		for(int b = 0; b < len; b++) {
			int a = sa[rk[b] - 1];
			while(a + h < len && s[a + h] == s[b + h]) ++h;
			lcp[rk[b] - 1] = h; if(h) --h; 
		}
	}
	void init(string _s) {
		s = _s; len = (int)s.size();
		getsa(); getlcp();
	}
	int bs_rit(string &t) {
		int l = 0, r = len + 1;
		while(l + 1 <= r - 1) {
			int mid = (l + r) >> 1;
			bool fl = 1; int st = sa[mid];
			for(int i = 0; i < (int)t.size(); i++) {
				if(st + i >= len || s[st + i] < t[i]) {
					break;
				}
				if(s[st + i] > t[i]) {
					fl = 0; break;
				}
			}
			if(fl) l = mid;
			else r = mid;
		}
		return l;
	}
	int bs_lft(string &t) {
		int l = 0, r = len + 1;
		while(l + 1 <= r - 1) {
			int mid = (l + r) >> 1;
			bool fl = 0; int st = sa[mid];
			for(int i = 0; i < (int)t.size(); i++) {
				if(st + i >= len || s[st + i] < t[i]) {
					fl = 1; break;
				}
				if(s[st + i] > t[i]) {
					break;
				}
			}
			if(fl) l = mid;
			else r = mid;
		}
		return r;
	}
}sa; // 不会写后缀自动机所以就放弃了(?)
// 二维数点离线怎么做啊
int ls[100005 << 5], rs[100005 << 5], sum[100005 << 5], rt[100005], tot;
int build(int l, int r) {
	int root = ++tot;
	if (l == r) return root;
	int mid = (l + r) >> 1;
	ls[root] = build(l, mid);
	rs[root] = build(mid + 1, r);
	return root;
} // 甚至是从oi-wiki抄的板子
int update(int k, int l, int r, int root) {
	int dir = ++tot;
	ls[dir] = ls[root], rs[dir] = rs[root], sum[dir] = sum[root] + 1;
	if (l == r) return dir;
	int mid = (l + r) >> 1;
	if (k <= mid)
		ls[dir] = update(k, l, mid, ls[dir]);
	else
		rs[dir] = update(k, mid + 1, r, rs[dir]);
  return dir;
}
int query(int u, int v, int l, int r, int ql, int qr) {
	int mid = (l + r) >> 1;
	if(ql <= l && r <= qr) return sum[v] - sum[u];
	int ans = 0;
	if(ql <= mid)
		ans += query(ls[u], ls[v], l, mid, ql, qr);
	if(mid + 1 <= qr)
		ans += query(rs[u], rs[v], mid + 1, r, ql, qr);
	return ans;
}
string s, t;
int n, q, l, r;
int main() {
	cin >> s >> q;
	sa.init(s); n = (int)s.size();
	/*for(int i = 0; i < n; i++) cout << sa.rk[i] << " ";
	cout << endl;
	for(int i = 1; i <= n; i++) cout << sa.sa[i] << " ";
	cout << endl;*/
	rt[0] = build(1, n);
	for(int i = 1; i <= n; i++)
		rt[i] = update(sa.rk[i - 1], 1, n, rt[i - 1]);
	while(q--) {
		cin >> l >> r >> t; l++; r++;
		int L = sa.bs_lft(t), R = sa.bs_rit(t);
		if(L > R || r - l + 1 < (int)t.size())
			cout << 0 << endl;
		else
			cout << query(rt[l - 1], rt[r - (int)t.size() + 1], 1, n, L, R) << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 32524
final_rank: 3

code_snippet: #include<bits/stdc++.h>
#define pb push_back
#define ll long long
using namespace std;
struct suffix_array {
	vector<int> sa, rk, lcp;
	//sa:后缀排序;rk:后缀名次;lcp:最长公共前缀
	int len; string s;
	void getsa() {
		sa.clear(); rk.clear(); sa.resize(len + 1, 0); rk.resize(len + 1, 0); sa[0] = len;
		for(int i = 1; i <= len; i++) sa[i] = i - 1;
		sort(sa.begin() + 1, sa.end(), [&](int a, int b) {return s[a] < s[b];});
		for(int i = 1; i <= len; i++) {
			int a = sa[i - 1], b = sa[i];
			if(i > 1 && s[a] == s[b]) rk[b] = rk[a];
			else rk[b] = i;
		}
		for(int siz = 1; siz <= len; siz *= 2) {
			vector<int> lsa(sa), lrk(rk), cnt(len + 1);
			for(int i = 0; i <= len; i++) cnt[i] = i;
			for(auto t : lsa) {
				int T = t - siz;
				if(T >= 0) sa[cnt[lrk[T]]++] = T;
			}
			for(int i = 1; i <= len; i++) {
				int a = sa[i - 1], b = sa[i];
				if(lrk[a] == lrk[b] && lrk[a + siz] == lrk[b + siz]) rk[b] = rk[a];
				else rk[b] = i;
			}
		}
	}
	void getlcp() {
		lcp.clear(); lcp.resize(len, 0); int h = 0;
		for(int b = 0; b < len; b++) {
			int a = sa[rk[b] - 1];
			while(a + h < len && s[a + h] == s[b + h]) ++h;
			lcp[rk[b] - 1] = h; if(h) --h; 
		}
	}
	void init(string _s) {
		s = _s; len = (int)s.size();
		getsa(); getlcp();
	}
	int bs_rit(string &t) {
		int l = 0, r = len + 1;
		while(l + 1 <= r - 1) {
			int mid = (l + r) >> 1;
			bool fl = 1; int st = sa[mid];
			for(int i = 0; i < (int)t.size(); i++) {
				if(st + i >= len || s[st + i] < t[i]) {
					break;
				}
				if(s[st + i] > t[i]) {
					fl = 0; break;
				}
			}
			if(fl) l = mid;
			else r = mid;
		}
		return l;
	}
	int bs_lft(string &t) {
		int l = 0, r = len + 1;
		while(l + 1 <= r - 1) {
			int mid = (l + r) >> 1;
			bool fl = 0; int st = sa[mid];
			for(int i = 0; i < (int)t.size(); i++) {
				if(st + i >= len || s[st + i] < t[i]) {
					fl = 1; break;
				}
				if(s[st + i] > t[i]) {
					break;
				}
			}
			if(fl) l = mid;
			else r = mid;
		}
		return r;
	}
}sa; // 不会写后缀自动机所以就放弃了(?)
// 二维数点离线怎么做啊
int ls[100005 << 4], rs[100005 << 4], sum[100005 << 4], rt[100005], tot;
int build(int l, int r) {
	int root = ++tot;
	if (l == r) return root;
	int mid = (l + r) >> 1;
	ls[root] = build(l, mid);
	rs[root] = build(mid + 1, r);
	return root;
} // 甚至是从oi-wiki抄的板子
int update(int k, int l, int r, int root) {
	int dir = ++tot;
	ls[dir] = ls[root], rs[dir] = rs[root], sum[dir] = sum[root] + 1;
	if (l == r) return dir;
	int mid = (l + r) >> 1;
	if (k <= mid)
		ls[dir] = update(k, l, mid, ls[dir]);
	else
		rs[dir] = update(k, mid + 1, r, rs[dir]);
  return dir;
}
int query(int u, int v, int l, int r, int ql, int qr) {
	int mid = (l + r) >> 1;
	if(ql <= l && r <= qr) return sum[v] - sum[u];
	int ans = 0;
	if(ql <= mid)
		ans += query(ls[u], ls[v], l, mid, ql, qr);
	if(mid + 1 <= qr)
		ans += query(rs[u], rs[v], mid + 1, r, ql, qr);
	return ans;
}
string s, t;
int n, q, l, r;
int main() {
	cin >> s >> q;
	sa.init(s); n = (int)s.size();
	/*for(int i = 0; i < n; i++) cout << sa.rk[i] << " ";
	cout << endl;
	for(int i = 1; i <= n; i++) cout << sa.sa[i] << " ";
	cout << endl;*/
	rt[0] = build(1, n);
	for(int i = 1; i <= n; i++)
		rt[i] = update(sa.rk[i - 1], 1, n, rt[i - 1]);
	while(q--) {
		cin >> l >> r >> t; l++; r++;
		int L = sa.bs_lft(t), R = sa.bs_rit(t);
		if(L > R || r - l + 1 < (int)t.size())
			cout << 0 << endl;
		else
			cout << query(rt[l - 1], rt[r - (int)t.size() + 1], 1, n, L, R) << endl;
	}
	return 0;
}
accuracy: 0.484375
time_ms: 140
memory_kb: 21912
final_rank: 19

code_snippet: #include <bits/stdc++.h>

using namespace std;

using i64 = int64_t;


// doc: https://shibh308.github.io/library/library/lib/classes/rollinghashmonoid.cpp.html
struct RollingHashMonoid{
    using Hash = RollingHashMonoid;
    using u64 = uint64_t;
    static constexpr u64 mod = (1uLL << 61) - 1;
    static constexpr u64 m30 = (1uLL << 30) - 1;
    static constexpr u64 m31 = (1uLL << 31) - 1;
    static constexpr u64 m61 = mod;
    static constexpr u64 _base = 550390130435464343;
    static constexpr u64 _base_inv = 1803816245541264939;
    static vector<u64> base, base_inv;

    static inline u64 calc_mod(u64 x){
        u64 xu = x >> 61;
        u64 xd = x & m61;
        u64 res = xu + xd;
        if(res >= mod)
            res -= mod;
        return res;
    }

    static inline u64 raw_mul(u64 a, u64 b){
        u64 au = a >> 31;
        u64 ad = a & m31;
        u64 bu = b >> 31;
        u64 bd = b & m31;
        u64 mid = ad * bu + au * bd;
        u64 midu = mid >> 30;
        u64 midd = mid & m30;
        return au * bu * 2 + midu + (midd << 31) + ad * bd;
    }

    static void remake_table(int len){
        while(base.size() <= len){
            base.emplace_back(calc_mod(raw_mul(base.back(), _base)));
            base_inv.emplace_back(calc_mod(raw_mul(base_inv.back(), _base_inv)));
        }
    }

    u64 h, l;

    static inline u64 lshift(u64 a, int len){
        remake_table(len);
        return raw_mul(a, base[len]);
    }
    static inline u64 rshift(u64 a, int len){
        remake_table(len);
        return raw_mul(a, base_inv[len]);
    }

    Hash concat(const Hash& b) const{
        return RollingHashMonoid(
                calc_mod(h + lshift(b.h, l)),
                l + b.l
        );
    }
    Hash sub(const Hash& b) const{
        return RollingHashMonoid(
                calc_mod(rshift(h + mod - b.h, b.l)),
                l - b.l
        );
    }

    RollingHashMonoid() : h(0), l(0){}
    RollingHashMonoid(u64 x) : h(x), l(1){}
    RollingHashMonoid(u64 h, u64 l) : h(h), l(l){}

    friend bool operator==(const Hash& a, const Hash& b){return a.h == b.h && a.l == b.l;}

    template <typename T>
    static vector<Hash> make(vector<T>& x){
        vector<Hash> v(x.size() + 1);
        for(int i = 0; i < x.size(); ++i){
            v[i + 1] = v[i].concat(x[i]);
        }
        return v;
    }
    static vector<Hash> make(string& x){
        vector<Hash> v(x.size() + 1);
        for(int i = 0; i < x.size(); ++i){
            v[i + 1] = v[i].concat(x[i]);
        }
        return v;
    }
};

namespace std{
template<> struct hash<RollingHashMonoid>{
    size_t operator()(const RollingHashMonoid x) const noexcept{
        return x.concat(x.l).h;
    }
};
}


using Hash = RollingHashMonoid;
vector<uint64_t> Hash::base = {1};
vector<uint64_t> Hash::base_inv = {1};


// doc: https://shibh308.github.io/library/library/lib/classes/hashmap.cpp.html
template <typename T, typename U, T del = numeric_limits<T>::max(), T null = numeric_limits<T>::max() - 1>
struct HashMap{
    static constexpr __int128_t z = 0xf332ac987401cba5;
    uint64_t n, q, d;

    vector<pair<T, U>> v;

    HashMap() : n(0), q(0), d(1),  v(2, make_pair(null, U())){
    }

    inline uint64_t hash(T key){return uint64_t((z * __int128_t(key)) >> (64 - d)) & ((1LL << d) - 1);}

    pair<U, bool> find(T x){
        for(uint64_t i = hash(x); v[i].first != null; i = (i + 1) & ((1 << d) - 1))
            if(v[i].first == x)
                return make_pair(v[i].second, true);
        return make_pair(U(), false);
    }

    bool add(T x, U val){
        if(find(x).second)
            return false;
        if(((q + 1) << 1) > (1 << d) || (1 << d) < 3 * n)
            resize();
        uint64_t i = hash(x);
        for(; v[i].first != null && v[i].first != del; i = (i + 1) & ((1 << d) - 1));
        q += (v[i].first == null);
        ++n;
        v[i] = make_pair(x, val);
        return true;
    }

    bool erase(T x){
        uint64_t i = hash(x);
        for(; v[i].first != null && v[i].first != x; i = (i + 1) & ((1 << d) - 1));
        if(v[i].first == null)
            return false;
        --n;
        v[i] = make_pair(del, U());
        return true;
    }

    void resize(){
        ++d;
        vector<pair<T, U>> old_table;
        q = n;
        swap(old_table, v);
        v.assign(1 << d, make_pair(null, U()));
        n = 0;
        for(int i = 0; i < old_table.size(); ++i)
            if(old_table[i].first != null && old_table[i].first != del)
                add(old_table[i].first, old_table[i].second);
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/avl_map.cpp.html
template <typename T, typename U>
struct AVL_map{
    struct Node{
        int height;
        T key;
        U val;
        Node(T key, U val) : key(key), val(val), height(1){c[0] = 0; c[1] = 0;}
        int c[2];
    };
    vector<Node> nodes;
    stack<int> st;
    AVL_map(){
        nodes.emplace_back(T(), U());
        nodes[0].height = 0;
    }
    template <bool inv>
    int balance_factor(int x){return (nodes[nodes[x].c[0]].height - nodes[nodes[x].c[1]].height) * (inv ? -1 : 1);}
    void _update(int x){
        if(x == 0)
            return;
        nodes[x].height = max(nodes[nodes[x].c[0]].height, nodes[nodes[x].c[1]].height) + 1;
    }
    template <bool is_right>
    int rotate(int x){
        int y = nodes[x].c[1 ^ is_right];
        nodes[x].c[1 ^ is_right] = nodes[y].c[0 ^ is_right];
        nodes[y].c[0 ^ is_right] = x;
        _update(x);
        _update(y);
        return y;
    }
    template <bool inv>
    int _balance(int x){
        if(balance_factor<inv>(x) == 2){
            if(balance_factor<inv>(nodes[x].c[0 ^ inv]) < 0)
                nodes[x].c[0 ^ inv] = rotate<inv>(nodes[x].c[0 ^ inv]);
            x = rotate<1 ^ inv>(x);
        }
        return x;
    }
    int balance(int x){
        x = _balance<false>(x);
        x = _balance<true>(x);
        _update(x);
        return x;
    }
    int add(int x, T key, U val){
        if(x == 0){
            if(st.empty()){
                nodes.emplace_back(key, val);
                return nodes.size() - 1;
            }
            else{
                int y = st.top();
                st.pop();
                nodes[y] = Node(key, val);
                return y;
            }
        }
        else if(key == nodes[x].key)
            nodes[x].val = val;
        else if(key < nodes[x].key)
            nodes[x].c[0] = add(nodes[x].c[0], key, val);
        else
            nodes[x].c[1] = add(nodes[x].c[1], key, val);
        x = balance(x);
        return x;
    }
    // 子が片方しかない時にノードを削除する
    int _erase_top(int x, bool del){
        for(int i = 0; i < 2; ++i){
            if(nodes[x].c[i] == 0){
                int y = nodes[x].c[i ^ 1];
                if(del)
                    st.push(x);
                return y;
            }
        }
        return 0;
    }
    // 最小の要素をdstにコピーしてから削除する
    int _copy_erase(int x, int dst, bool del){
        if(nodes[x].c[0] == 0){
            nodes[dst].val = nodes[x].val;
            return _erase_top(x, del);
        }
        nodes[x].c[0] = _copy_erase(nodes[x].c[0], dst, del);
        x = balance(x);
        return x;
    }
    int erase(int x, T key, bool del = true){
        if(key < nodes[x].key)
            nodes[x].c[0] = erase(nodes[x].c[0], key, del);
        else if(nodes[x].key < key)
            nodes[x].c[1] = erase(nodes[x].c[1], key, del);
        else{
            if(nodes[x].c[0] == 0 || nodes[x].c[1] == 0)
                return _erase_top(x, del);
            nodes[x].c[1] = _copy_erase(nodes[x].c[1], x, del);
        }
        x = balance(x);
        return x;
    }
    pair<U, bool> get(int x, T key){
        if(x == 0)
            return {U(), false};
        else if(key == nodes[x].key)
            return {nodes[x].val, true};
        else if(key < nodes[x].key)
            return get(nodes[x].c[0], key);
        else
            return get(nodes[x].c[1], key);
    }
    vector<pair<T, U>> list(int x){
        vector<pair<T, U>> v;
        stack<pair<int,bool>> sta;
        sta.emplace(x, false);
        bool add;
        while(!sta.empty()){
            tie(x, add) = sta.top();
            sta.pop();
            if(x == 0)
                continue;
            if(add)
                v.emplace_back(nodes[x].key, nodes[x].val);
            else{
                if(nodes[x].c[1])
                    sta.emplace(nodes[x].c[1], false);
                sta.emplace(x, true);
                if(nodes[x].c[0])
                    sta.emplace(nodes[x].c[0], false);
            }
        }
        return v;
    }
};


struct HashPatriciaTree{
    struct Node{
        bool is_elm = false;
        int ch = 0;
        int len = 0;
        int par = -1;
        int data_idx = -1;
        Hash hash;
    };

    static int fat(int l, int r){
        return r & (-1 << (31 - __builtin_clz(l ^ r)));
    };

    AVL_map<int,int> avl;
    vector<function<Hash(int)>> hash_func;
    vector<Node> nodes;
    HashMap<uint64_t, int> hmap;
    vector<int> idxes;

    HashPatriciaTree() : nodes(1){
    }

    void make_fat(int x){
        int st = nodes[nodes[x].par].len;
        int en = nodes[x].len;
        int fa = fat(st, en);
        auto ha = hash_func[nodes[x].data_idx](fa);
        nodes[x].hash = ha;
        hmap.add(ha.concat(ha.l).h, x);
    }

    void make(int idx, int target, int len, int label){
        nodes.emplace_back();
        nodes.back().len = len;
        nodes.back().data_idx = idx;
        nodes.back().par = target;
        nodes[target].ch = avl.add(nodes[target].ch, label, nodes.size() - 1);
        make_fat(nodes.size() - 1);
    }

    void split(int idx, int target, int len, int match_len, int new_label, int root_label, int branch_label){
        int par = nodes[target].par;
        nodes.emplace_back();
        nodes.back().len = match_len;
        nodes.back().data_idx = idx;
        nodes.back().par = par;

        Hash ha = nodes[target].hash;
        hmap.erase(ha.concat(ha.l).h);

        nodes[par].ch = avl.add(nodes[par].ch, root_label, nodes.size() - 1);
        nodes.back().ch = avl.add(nodes.back().ch, branch_label, target);
        nodes[target].par = nodes.size() - 1;
        int target_siz = nodes.size() - 1;
        if(nodes.back().len != len)
            make(idx, nodes.size() - 1, len, new_label);
        make_fat(target);
        make_fat(target_siz);
    }

    int access(function<Hash(int)>& f, int i){
        return f(i + 1).sub(f(i)).h;
    }

    // f(x): 長さxのprefixのハッシュを返す
    // g(x): x文字目を返す
    void insert(int m, function<Hash(int)> f){
        hash_func.emplace_back(f);
        int len, x;
        tie(len, x) = match(m, f);
        assert(!(len || x) || (nodes[nodes[x].par].len < len && len <= nodes[x].len));
        if(len == nodes[x].len){
            if(len == m){
                idxes.emplace_back(x);
                nodes[x].data_idx = idxes.size() - 1;
                nodes[x].is_elm = true;
                return;
            }
            else
                make(idxes.size(), x, m, access(f, len));
        }
        else{
            split(idxes.size(), x, m, len, access(f, len), access(hash_func[nodes[x].data_idx], nodes[nodes[x].par].len), access(hash_func[nodes[x].data_idx], len));
        }
        idxes.emplace_back(nodes.size() - 1);
        nodes.back().is_elm = true;
    }

    int lcp(int ok, int ng, function<Hash(int)> f, function<Hash(int)> g){
        while(ng - ok > 1){
            int mid = (ok + ng) >> 1;
            (f(mid) == g(mid) ? ok : ng) = mid;
        }
        return ok;
    }

    // (マッチ長, ノード)
    pair<int,int> match(int m, function<Hash(int)> f){
        int ok = 0, ng = m + 1;
        int x = 0;
        int ok_len = 0;
        while(ng - ok > 1){
            int mid = fat(ok + 1, ng - 1);
            Hash h = f(mid);
            int idx;
            bool fl;
            tie(idx, fl) = hmap.find(h.concat(h.l).h);
            if(fl){
                x = idx;
                ok_len = ok;
                ok = nodes[x].len;
            }
            else{
                ng = mid;
            }
        }
        int match_len;
        if(ok == 0){
            match_len = 0;
        }
        else{
            match_len = lcp(ok_len, min(m, nodes[x].len) + 1, f, hash_func[nodes[x].data_idx]);
            if(match_len < nodes[x].len){
                return {match_len, x};
            }
        }
        int label = access(f, ok);
        int ch;
        bool fl;
        tie(ch, fl) = avl.get(nodes[x].ch, label);
        if(!fl){
            assert(match_len <= m);
            return {match_len, x};
        }
        match_len = lcp(match_len, min(m, nodes[ch].len) + 1, f, hash_func[nodes[ch].data_idx]);
        assert(match_len <= m);
        return {match_len, ch};
    }
    static function<Hash(int)> build(vector<Hash>& v){
        return [&v](int i){
            return v[i];
        };
    }
    static vector<function<Hash(int)>> build_suffix(vector<Hash>& v){
        vector<function<Hash(int)>> fv;
        vector<function<int(int)>> gv;
        for(int j = 0; j < v.size() - 1; ++j){
            fv.emplace_back([j, &v](int i){
                return v[i + j].sub(v[j]);
            });
        }
        return fv;
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/bitvector.cpp.html
struct BitVector{
    vector<uint64_t> v;
    vector<int> r;
    BitVector(){}
    void build(){
        r.assign(v.size() + 1, 0);
        for(int i = 0; i < v.size(); ++i)
            r[i + 1] = r[i] + __builtin_popcountll(v[i]);
    }
    bool access(int x){
        return (v[x >> 6] >> (x & 63)) & 1;
    }
    // [0, x)の1の出現回数
    int rank(int x){
        return r[x >> 6] + __builtin_popcountll(v[x >> 6] & ((1uLL << (x & 63)) - 1));
    }
    int rank(int x, bool fl){
        return fl ? rank(x) : x - rank(x);
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/waveletmatrix.cpp.html
template <typename T, int W>
struct WaveletMatrix{

    array<BitVector, W> bv;
    array<int, W> zero_cnt;

    WaveletMatrix(vector<T>& a){
        int n = a.size();
        vector<T> v(a);
        for(int i = W - 1; i >= 0; --i){
            vector<uint64_t> b((n >> 6) + 1, 0);
            vector<T> v1, v2;
            for(int j = 0; j < n; ++j){
                ((v[j] >> i) & 1 ? v2 : v1).push_back(v[j]);
                b[j >> 6] |= uint64_t((v[j] >> i) & 1) << (j & 63);
            }
            for(int j = 0; j < v.size(); ++j)
                v[j] = (j < v1.size() ? v1[j] : v2[j - v1.size()]);
            bv[i].v = move(b);
            bv[i].build();
            zero_cnt[i] = bv[i].rank(n, 0);
        }
    }

    // [l, r)内のxの数
    int count(int l, int r, T x){
        for(int i = W - 1; i >= 0; --i){
            bool fl = (x >> i) & 1;
            int st = bv[i].rank(l, fl);
            int en = bv[i].rank(r, fl);
            l = (fl ? zero_cnt[i] : 0) + st;
            r = (fl ? zero_cnt[i] : 0) + en;
        }
        return r - l;
    }

    // [l, r)内で[0, x)を満たす値の数
    int count_lower(int l, int r, T x){
        int cnt = 0;
        for(int i = W - 1; i >= 0; --i){
            bool fl = (x >> i) & 1;
            int st = bv[i].rank(l, fl);
            int en = bv[i].rank(r, fl);
            if(fl){
                st += zero_cnt[i];
                en += zero_cnt[i];
                cnt += (bv[i].rank(r, 0) - bv[i].rank(l, 0));
            }
            l = st, r = en;
        }
        return cnt;
    }

    // [l, r)内で[x, y)を満たす値の数
    int count_range(int l, int r, T x, T y){
        return count_lower(l, r, y) - count_lower(l, r, x);
    }

    // 0-indexedでk番目に小さいものを返す
    T kth_min(int l, int r, int k){
        T ans = 0;
        for(int i = W - 1; i >= 0; --i){
            int st = bv[i].rank(l, 0);
            int en = bv[i].rank(r, 0);
            if(en - st <= k){
                k -= en - st;
                l = zero_cnt[i] + bv[i].rank(l, 1);
                r = zero_cnt[i] + bv[i].rank(r, 1);
                ans |= (1uLL << i);
            }
            else{
                l = st, r = en;
            }
        }
        return ans;
    }

    // [l, r)でのx以上最小値
    pair<T, bool> predecessor(int l, int r, T x){
        int idx = count_lower(l, r, x);
        if(idx == r - l){
            return make_pair((1uLL << W) - 1, false);
        }
        return make_pair(kth_min(l, r, idx), true);
    }

    // [l, r)でのx以下最大値
    pair<T, bool> successor(int l, int r, T x){
        int idx = count_lower(l, r, x + 1);
        if(idx == 0)
            return make_pair(0, false);
        return make_pair(kth_min(l, r, idx - 1), true);
    }
};


signed main(){
    HashPatriciaTree tree;
    string s;
    int q;
    cin >> s >> q;

    int n = s.size();
    vector<Hash> sh = Hash::make(s);
    auto s_res = HashPatriciaTree::build_suffix(sh);
    for(int i = 0; i < n; ++i){
        tree.insert(n - i, s_res[i]);
    }

    vector<int> v;
    int k = tree.nodes.size();
    vector<int> in(k), out(k);
    function<void(int)> f = [&](int x){
        in[x] = v.size();
        v.emplace_back(tree.nodes[x].is_elm ? tree.nodes[x].data_idx : n);
        for(auto p : tree.avl.list(tree.nodes[x].ch)){
            f(p.second);
        }
        out[x] = v.size();
    };
    f(0);

    WaveletMatrix<int, 20> wm(v);

    for(int i = 0; i < q; ++i){
        int l, r;
        string t;
        cin >> l >> r >> t;
        ++r;
        auto h = Hash::make(t);
        auto res = HashPatriciaTree::build(h);
        int len, node;
        tie(len, node) = tree.match(t.size(), res);
        if(len < t.size()){
            cout << 0 << endl;
            continue;
        }
        int in_x = in[node];
        int out_x = out[node];

        int left = l;
        int right = max(left, min(int(v.size()), r + 1 - int(t.size())));
        if(right <= left)
            cout << 0 << endl;
        else
            cout << wm.count_range(in_x, out_x, left, right) << endl;
    }
}
accuracy: 0.515625
time_ms: 220
memory_kb: 36160
final_rank: 17

code_snippet: #line 1 "aoj_1585.test.cpp"
#define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1585"

#include <bits/stdc++.h>

using namespace std;

using i64 = int64_t;

#line 1 "/home/shibh308/workspace/compro/competitive-programming/library/lib/classes/rollinghashmonoid.cpp"
struct RollingHashMonoid{
    using Hash = RollingHashMonoid;
    using u64 = uint64_t;
    static constexpr u64 mod = (1uLL << 61) - 1;
    static constexpr u64 m30 = (1uLL << 30) - 1;
    static constexpr u64 m31 = (1uLL << 31) - 1;
    static constexpr u64 m61 = mod;
    static constexpr u64 _base = 550390130435464343;
    static constexpr u64 _base_inv = 1803816245541264939;
    static vector<u64> base, base_inv;

    static inline u64 calc_mod(u64 x){
        u64 xu = x >> 61;
        u64 xd = x & m61;
        u64 res = xu + xd;
        if(res >= mod)
            res -= mod;
        return res;
    }

    static inline u64 raw_mul(u64 a, u64 b){
        u64 au = a >> 31;
        u64 ad = a & m31;
        u64 bu = b >> 31;
        u64 bd = b & m31;
        u64 mid = ad * bu + au * bd;
        u64 midu = mid >> 30;
        u64 midd = mid & m30;
        return au * bu * 2 + midu + (midd << 31) + ad * bd;
    }

    static void remake_table(int len){
        while(base.size() <= len){
            base.emplace_back(calc_mod(raw_mul(base.back(), _base)));
            base_inv.emplace_back(calc_mod(raw_mul(base_inv.back(), _base_inv)));
        }
    }

    u64 h, l;

    static inline u64 lshift(u64 a, int len){
        remake_table(len);
        return raw_mul(a, base[len]);
    }
    static inline u64 rshift(u64 a, int len){
        remake_table(len);
        return raw_mul(a, base_inv[len]);
    }

    Hash concat(const Hash& b) const{
        return RollingHashMonoid(
                calc_mod(h + lshift(b.h, l)),
                l + b.l
        );
    }
    Hash sub(const Hash& b) const{
        return RollingHashMonoid(
                calc_mod(rshift(h + mod - b.h, b.l)),
                l - b.l
        );
    }

    RollingHashMonoid() : h(0), l(0){}
    RollingHashMonoid(u64 x) : h(x), l(1){}
    RollingHashMonoid(u64 h, u64 l) : h(h), l(l){}

    friend bool operator==(const Hash& a, const Hash& b){return a.h == b.h && a.l == b.l;}

    template <typename T>
    static vector<Hash> make(vector<T>& x){
        vector<Hash> v(x.size() + 1);
        for(int i = 0; i < x.size(); ++i){
            v[i + 1] = v[i].concat(x[i]);
        }
        return v;
    }
    static vector<Hash> make(string& x){
        vector<Hash> v(x.size() + 1);
        for(int i = 0; i < x.size(); ++i){
            v[i + 1] = v[i].concat(x[i]);
        }
        return v;
    }
};

namespace std{
template<> struct hash<RollingHashMonoid>{
    size_t operator()(const RollingHashMonoid x) const noexcept{
        return x.concat(x.l).h;
    }
};
}


using Hash = RollingHashMonoid;
vector<uint64_t> Hash::base = {1};
vector<uint64_t> Hash::base_inv = {1};
#line 1 "/home/shibh308/workspace/compro/competitive-programming/library/lib/classes/hashmap.cpp"
template <typename T, typename U, T del = numeric_limits<T>::max(), T null = numeric_limits<T>::max() - 1>
struct HashMap{
    static constexpr __int128_t z = 0xf332ac987401cba5;
    uint64_t n, q, d;

    vector<pair<T, U>> v;

    HashMap() : n(0), q(0), d(1),  v(2, make_pair(null, U())){
    }

    inline uint64_t hash(T key){return uint64_t((z * __int128_t(key)) >> (64 - d)) & ((1LL << d) - 1);}

    pair<U, bool> find(T x){
        for(uint64_t i = hash(x); v[i].first != null; i = (i + 1) & ((1 << d) - 1))
            if(v[i].first == x)
                return make_pair(v[i].second, true);
        return make_pair(U(), false);
    }

    bool add(T x, U val){
        if(find(x).second)
            return false;
        if(((q + 1) << 1) > (1 << d) || (1 << d) < 3 * n)
            resize();
        uint64_t i = hash(x);
        for(; v[i].first != null && v[i].first != del; i = (i + 1) & ((1 << d) - 1));
        q += (v[i].first == null);
        ++n;
        v[i] = make_pair(x, val);
        return true;
    }

    bool erase(T x){
        uint64_t i = hash(x);
        for(; v[i].first != null && v[i].first != x; i = (i + 1) & ((1 << d) - 1));
        if(v[i].first == null)
            return false;
        --n;
        v[i] = make_pair(del, U());
        return true;
    }

    void resize(){
        ++d;
        vector<pair<T, U>> old_table;
        q = n;
        swap(old_table, v);
        v.assign(1 << d, make_pair(null, U()));
        n = 0;
        for(int i = 0; i < old_table.size(); ++i)
            if(old_table[i].first != null && old_table[i].first != del)
                add(old_table[i].first, old_table[i].second);
    }
};
#line 1 "/home/shibh308/workspace/compro/competitive-programming/library/lib/classes/avl_map.cpp"
template <typename T, typename U>
struct AVL_map{
    struct Node{
        int height;
        T key;
        U val;
        Node(T key, U val) : key(key), val(val), height(1){c[0] = 0; c[1] = 0;}
        int c[2];
    };
    vector<Node> nodes;
    stack<int> st;
    AVL_map(){
        nodes.emplace_back(T(), U());
        nodes[0].height = 0;
    }
    template <bool inv>
    int balance_factor(int x){return (nodes[nodes[x].c[0]].height - nodes[nodes[x].c[1]].height) * (inv ? -1 : 1);}
    void _update(int x){
        if(x == 0)
            return;
        nodes[x].height = max(nodes[nodes[x].c[0]].height, nodes[nodes[x].c[1]].height) + 1;
    }
    template <bool is_right>
    int rotate(int x){
        int y = nodes[x].c[1 ^ is_right];
        nodes[x].c[1 ^ is_right] = nodes[y].c[0 ^ is_right];
        nodes[y].c[0 ^ is_right] = x;
        _update(x);
        _update(y);
        return y;
    }
    template <bool inv>
    int _balance(int x){
        if(balance_factor<inv>(x) == 2){
            if(balance_factor<inv>(nodes[x].c[0 ^ inv]) < 0)
                nodes[x].c[0 ^ inv] = rotate<inv>(nodes[x].c[0 ^ inv]);
            x = rotate<1 ^ inv>(x);
        }
        return x;
    }
    int balance(int x){
        x = _balance<false>(x);
        x = _balance<true>(x);
        _update(x);
        return x;
    }
    int add(int x, T key, U val){
        if(x == 0){
            if(st.empty()){
                nodes.emplace_back(key, val);
                return nodes.size() - 1;
            }
            else{
                int y = st.top();
                st.pop();
                nodes[y] = Node(key, val);
                return y;
            }
        }
        else if(key == nodes[x].key)
            nodes[x].val = val;
        else if(key < nodes[x].key)
            nodes[x].c[0] = add(nodes[x].c[0], key, val);
        else
            nodes[x].c[1] = add(nodes[x].c[1], key, val);
        x = balance(x);
        return x;
    }
    // 子が片方しかない時にノードを削除する
    int _erase_top(int x, bool del){
        for(int i = 0; i < 2; ++i){
            if(nodes[x].c[i] == 0){
                int y = nodes[x].c[i ^ 1];
                if(del)
                    st.push(x);
                return y;
            }
        }
        return 0;
    }
    // 最小の要素をdstにコピーしてから削除する
    int _copy_erase(int x, int dst, bool del){
        if(nodes[x].c[0] == 0){
            nodes[dst].val = nodes[x].val;
            return _erase_top(x, del);
        }
        nodes[x].c[0] = _copy_erase(nodes[x].c[0], dst, del);
        x = balance(x);
        return x;
    }
    int erase(int x, T key, bool del = true){
        if(key < nodes[x].key)
            nodes[x].c[0] = erase(nodes[x].c[0], key, del);
        else if(nodes[x].key < key)
            nodes[x].c[1] = erase(nodes[x].c[1], key, del);
        else{
            if(nodes[x].c[0] == 0 || nodes[x].c[1] == 0)
                return _erase_top(x, del);
            nodes[x].c[1] = _copy_erase(nodes[x].c[1], x, del);
        }
        x = balance(x);
        return x;
    }
    pair<U, bool> get(int x, T key){
        if(x == 0)
            return {U(), false};
        else if(key == nodes[x].key)
            return {nodes[x].val, true};
        else if(key < nodes[x].key)
            return get(nodes[x].c[0], key);
        else
            return get(nodes[x].c[1], key);
    }
    vector<pair<T, U>> list(int x){
        vector<pair<T, U>> v;
        stack<pair<int,bool>> sta;
        sta.emplace(x, false);
        bool add;
        while(!sta.empty()){
            tie(x, add) = sta.top();
            sta.pop();
            if(x == 0)
                continue;
            if(add)
                v.emplace_back(nodes[x].key, nodes[x].val);
            else{
                if(nodes[x].c[1])
                    sta.emplace(nodes[x].c[1], false);
                sta.emplace(x, true);
                if(nodes[x].c[0])
                    sta.emplace(nodes[x].c[0], false);
            }
        }
        return v;
    }
};
#line 1 "/home/shibh308/workspace/compro/competitive-programming/library/lib/classes/hashpatriciatree.cpp"
struct HashPatriciaTree{
    struct Node{
        bool is_elm = false;
        int ch = 0;
        int len = 0;
        int par = -1;
        int data_idx = -1;
        Hash hash;
    };

    static int fat(int l, int r){
        return r & (-1 << (31 - __builtin_clz(l ^ r)));
    };

    AVL_map<int,int> avl;
    vector<function<Hash(int)>> hash_func;
    vector<function<int(int)>> access_func;
    vector<Node> nodes;
    HashMap<uint64_t, int> hmap;
    vector<int> idxes;

    HashPatriciaTree() : nodes(1){
    }

    void make_fat(int x){
        int st = nodes[nodes[x].par].len;
        int en = nodes[x].len;
        int fa = fat(st, en);
        auto ha = hash_func[nodes[x].data_idx](fa);
        nodes[x].hash = ha;
        hmap.add(ha.concat(ha.l).h, x);
    }

    void make(int idx, int target, int len, int label){
        nodes.emplace_back();
        nodes.back().len = len;
        nodes.back().data_idx = idx;
        nodes.back().par = target;
        nodes[target].ch = avl.add(nodes[target].ch, label, nodes.size() - 1);
        make_fat(nodes.size() - 1);
    }

    void split(int idx, int target, int len, int match_len, int new_label, int root_label, int branch_label){
        int par = nodes[target].par;
        nodes.emplace_back();
        nodes.back().len = match_len;
        nodes.back().data_idx = idx;
        nodes.back().par = par;

        Hash ha = nodes[target].hash;
        hmap.erase(ha.concat(ha.l).h);

        nodes[par].ch = avl.add(nodes[par].ch, root_label, nodes.size() - 1);
        nodes.back().ch = avl.add(nodes.back().ch, branch_label, target);
        nodes[target].par = nodes.size() - 1;
        int target_siz = nodes.size() - 1;
        if(nodes.back().len != len)
            make(idx, nodes.size() - 1, len, new_label);
        make_fat(target);
        make_fat(target_siz);
    }

    // f(x): 長さxのprefixのハッシュを返す
    // g(x): x文字目を返す
    void insert(int m, function<Hash(int)> f, function<int(int)> g){
        hash_func.emplace_back(f);
        access_func.emplace_back(g);
        int len, x;
        tie(len, x) = match(m, f, g);
        assert(!(len || x) || (nodes[nodes[x].par].len < len && len <= nodes[x].len));
        if(len == nodes[x].len){
            if(len == m){
                idxes.emplace_back(x);
                nodes[x].data_idx = idxes.size() - 1;
                nodes[x].is_elm = true;
                return;
            }
            else
                make(idxes.size(), x, m, g(len));
        }
        else{
            split(idxes.size(), x, m, len, g(len), access_func[nodes[x].data_idx](nodes[nodes[x].par].len), access_func[nodes[x].data_idx](len));
        }
        idxes.emplace_back(nodes.size() - 1);
        nodes.back().is_elm = true;
    }

    int lcp(int ok, int ng, function<Hash(int)> f, function<Hash(int)> g){
        while(ng - ok > 1){
            int mid = (ok + ng) >> 1;
            (f(mid) == g(mid) ? ok : ng) = mid;
        }
        return ok;
    }

    // (マッチ長, ノード)
    pair<int,int> match(int m, function<Hash(int)> f, function<int(int)> g){
        int ok = 0, ng = m + 1;
        int x = 0;
        int ok_len = 0;
        while(ng - ok > 1){
            int mid = fat(ok + 1, ng - 1);
            Hash h = f(mid);
            int idx;
            bool fl;
            tie(idx, fl) = hmap.find(h.concat(h.l).h);
            if(fl){
                x = idx;
                ok_len = ok;
                ok = nodes[x].len;
            }
            else{
                ng = mid;
            }
        }
        int match_len;
        if(ok == 0){
            match_len = 0;
        }
        else{
            match_len = lcp(ok_len, min(m, nodes[x].len) + 1, f, hash_func[nodes[x].data_idx]);
            if(match_len < nodes[x].len){
                return {match_len, x};
            }
        }
        int label = g(ok);
        int ch;
        bool fl;
        tie(ch, fl) = avl.get(nodes[x].ch, label);
        if(!fl){
            assert(match_len <= m);
            return {match_len, x};
        }
        match_len = lcp(match_len, min(m, nodes[ch].len) + 1, f, hash_func[nodes[ch].data_idx]);
        assert(match_len <= m);
        return {match_len, ch};
    }
    template<typename T>
    static pair<function<Hash(int)>, function<int(int)>> build(T& s, vector<Hash>& v){
        auto f = [&v](int i){
            return v[i];
        };
        auto g = [&s](int i){
            return s[i];
        };
        return {f, g};
    }
    template<typename T>
    static pair<vector<function<Hash(int)>>, vector<function<int(int)>>> build_suffix(T& s, vector<Hash>& v){
        vector<function<Hash(int)>> fv;
        vector<function<int(int)>> gv;
        for(int j = 0; j < s.size(); ++j){
            auto f = [j, &v](int i){
                return v[i + j].sub(v[j]);
            };
            auto g = [j, &s](int i){
                return s[i + j];
            };
            fv.emplace_back(f);
            gv.emplace_back(g);
        }
        return {fv, gv};
    }
};
#line 1 "/home/shibh308/workspace/compro/competitive-programming/library/lib/classes/bitvector.cpp"
struct BitVector{
    vector<uint64_t> v;
    vector<int> r;
    BitVector(){}
    void build(){
        r.assign(v.size() + 1, 0);
        for(int i = 0; i < v.size(); ++i)
            r[i + 1] = r[i] + __builtin_popcountll(v[i]);
    }
    bool access(int x){
        return (v[x >> 6] >> (x & 63)) & 1;
    }
    // [0, x)の1の出現回数
    int rank(int x){
        return r[x >> 6] + __builtin_popcountll(v[x >> 6] & ((1uLL << (x & 63)) - 1));
    }
    int rank(int x, bool fl){
        return fl ? rank(x) : x - rank(x);
    }
};

#line 1 "/home/shibh308/workspace/compro/competitive-programming/library/lib/classes/waveletmatrix.cpp"
template <typename T, int W>
struct WaveletMatrix{

    array<BitVector, W> bv;
    array<int, W> zero_cnt;

    WaveletMatrix(vector<T>& a){
        int n = a.size();
        vector<T> v(a);
        for(int i = W - 1; i >= 0; --i){
            vector<uint64_t> b((n >> 6) + 1, 0);
            vector<T> v1, v2;
            for(int j = 0; j < n; ++j){
                ((v[j] >> i) & 1 ? v2 : v1).push_back(v[j]);
                b[j >> 6] |= uint64_t((v[j] >> i) & 1) << (j & 63);
            }
            for(int j = 0; j < v.size(); ++j)
                v[j] = (j < v1.size() ? v1[j] : v2[j - v1.size()]);
            bv[i].v = move(b);
            bv[i].build();
            zero_cnt[i] = bv[i].rank(n, 0);
        }
    }

    // [l, r)内のxの数
    int count(int l, int r, T x){
        for(int i = W - 1; i >= 0; --i){
            bool fl = (x >> i) & 1;
            int st = bv[i].rank(l, fl);
            int en = bv[i].rank(r, fl);
            l = (fl ? zero_cnt[i] : 0) + st;
            r = (fl ? zero_cnt[i] : 0) + en;
        }
        return r - l;
    }

    // [l, r)内で[0, x)を満たす値の数
    int count_lower(int l, int r, T x){
        int cnt = 0;
        for(int i = W - 1; i >= 0; --i){
            bool fl = (x >> i) & 1;
            int st = bv[i].rank(l, fl);
            int en = bv[i].rank(r, fl);
            if(fl){
                st += zero_cnt[i];
                en += zero_cnt[i];
                cnt += (bv[i].rank(r, 0) - bv[i].rank(l, 0));
            }
            l = st, r = en;
        }
        return cnt;
    }

    // [l, r)内で[x, y)を満たす値の数
    int count_range(int l, int r, T x, T y){
        return count_lower(l, r, y) - count_lower(l, r, x);
    }

    // 0-indexedでk番目に小さいものを返す
    T kth_min(int l, int r, int k){
        T ans = 0;
        for(int i = W - 1; i >= 0; --i){
            int st = bv[i].rank(l, 0);
            int en = bv[i].rank(r, 0);
            if(en - st <= k){
                k -= en - st;
                l = zero_cnt[i] + bv[i].rank(l, 1);
                r = zero_cnt[i] + bv[i].rank(r, 1);
                ans |= (1uLL << i);
            }
            else{
                l = st, r = en;
            }
        }
        return ans;
    }

    // [l, r)でのx以上最小値
    pair<T, bool> predecessor(int l, int r, T x){
        int idx = count_lower(l, r, x);
        if(idx == r - l){
            return make_pair((1uLL << W) - 1, false);
        }
        return make_pair(kth_min(l, r, idx), true);
    }

    // [l, r)でのx以下最大値
    pair<T, bool> successor(int l, int r, T x){
        int idx = count_lower(l, r, x + 1);
        if(idx == 0)
            return make_pair(0, false);
        return make_pair(kth_min(l, r, idx - 1), true);
    }
};

#line 15 "aoj_1585.test.cpp"


signed main(){
    HashPatriciaTree tree;
    string s;
    int q;
    cin >> s >> q;

    int n = s.size();
    vector<Hash> sh = Hash::make(s);
    auto s_res = HashPatriciaTree::build_suffix(s, sh);
    for(int i = 0; i < n; ++i){
        tree.insert(n - i, s_res.first[i], s_res.second[i]);
    }

    vector<int> v;
    int k = tree.nodes.size();
    vector<int> in(k), out(k);
    function<void(int)> f = [&](int x){
        in[x] = v.size();
        v.emplace_back(tree.nodes[x].is_elm ? tree.nodes[x].data_idx : n);
        for(auto p : tree.avl.list(tree.nodes[x].ch)){
            f(p.second);
        }
        out[x] = v.size();
    };
    f(0);

    WaveletMatrix<int, 20> wm(v);

    for(int i = 0; i < q; ++i){
        int l, r;
        string t;
        cin >> l >> r >> t;
        ++r;
        auto h = Hash::make(t);
        auto res = HashPatriciaTree::build(t, h);
        int len, node;
        tie(len, node) = tree.match(t.size(), res.first, res.second);
        if(len < t.size()){
            cout << 0 << endl;
            continue;
        }
        int in_x = in[node];
        int out_x = out[node];

        int left = l;
        int right = max(left, min(int(v.size()), r + 1 - int(t.size())));
        if(right <= left)
            cout << 0 << endl;
        else
            cout << wm.count_range(in_x, out_x, left, right) << endl;
    }
}
accuracy: 1
time_ms: 330
memory_kb: 65444
final_rank: 6

code_snippet: #include <bits/stdc++.h>

using namespace std;

using i64 = int64_t;


// doc: https://shibh308.github.io/library/library/lib/classes/rollinghashmonoid.cpp.html
struct RollingHashMonoid{
    using Hash = RollingHashMonoid;
    using u64 = uint64_t;
    static constexpr u64 mod = (1uLL << 61) - 1;
    static constexpr u64 m30 = (1uLL << 30) - 1;
    static constexpr u64 m31 = (1uLL << 31) - 1;
    static constexpr u64 m61 = mod;
    static constexpr u64 _base = 550390130435464343;
    static constexpr u64 _base_inv = 1803816245541264939;
    static vector<u64> base, base_inv;

    static inline u64 calc_mod(u64 x){
        u64 xu = x >> 61;
        u64 xd = x & m61;
        u64 res = xu + xd;
        if(res >= mod)
            res -= mod;
        return res;
    }

    static inline u64 raw_mul(u64 a, u64 b){
        u64 au = a >> 31;
        u64 ad = a & m31;
        u64 bu = b >> 31;
        u64 bd = b & m31;
        u64 mid = ad * bu + au * bd;
        u64 midu = mid >> 30;
        u64 midd = mid & m30;
        return au * bu * 2 + midu + (midd << 31) + ad * bd;
    }

    static void remake_table(int len){
        while(base.size() <= len){
            base.emplace_back(calc_mod(raw_mul(base.back(), _base)));
            base_inv.emplace_back(calc_mod(raw_mul(base_inv.back(), _base_inv)));
        }
    }

    u64 h, l;

    static inline u64 lshift(u64 a, int len){
        remake_table(len);
        return raw_mul(a, base[len]);
    }
    static inline u64 rshift(u64 a, int len){
        remake_table(len);
        return raw_mul(a, base_inv[len]);
    }

    Hash concat(const Hash& b) const{
        return RollingHashMonoid(
                calc_mod(h + lshift(b.h, l)),
                l + b.l
        );
    }
    Hash sub(const Hash& b) const{
        return RollingHashMonoid(
                calc_mod(rshift(h + mod - b.h, b.l)),
                l - b.l
        );
    }

    RollingHashMonoid() : h(0), l(0){}
    RollingHashMonoid(u64 x) : h(x), l(1){}
    RollingHashMonoid(u64 h, u64 l) : h(h), l(l){}

    friend bool operator==(const Hash& a, const Hash& b){return a.h == b.h && a.l == b.l;}

    template <typename T>
    static vector<Hash> make(vector<T>& x){
        vector<Hash> v(x.size() + 1);
        for(int i = 0; i < x.size(); ++i){
            v[i + 1] = v[i].concat(x[i]);
        }
        return v;
    }
    static vector<Hash> make(string& x){
        vector<Hash> v(x.size() + 1);
        for(int i = 0; i < x.size(); ++i){
            v[i + 1] = v[i].concat(x[i]);
        }
        return v;
    }
};

namespace std{
template<> struct hash<RollingHashMonoid>{
    size_t operator()(const RollingHashMonoid x) const noexcept{
        return x.concat(x.l).h;
    }
};
}


using Hash = RollingHashMonoid;
vector<uint64_t> Hash::base = {1};
vector<uint64_t> Hash::base_inv = {1};


// doc: https://shibh308.github.io/library/library/lib/classes/hashmap.cpp.html
template <typename T, typename U, T del = numeric_limits<T>::max(), T null = numeric_limits<T>::max() - 1>
struct HashMap{
    static constexpr __int128_t z = 0xf332ac987401cba5;
    uint64_t n, q, d;

    vector<pair<T, U>> v;

    HashMap() : n(0), q(0), d(1),  v(2, make_pair(null, U())){
    }

    inline uint64_t hash(T key){return uint64_t((z * __int128_t(key)) >> (64 - d)) & ((1LL << d) - 1);}

    pair<U, bool> find(T x){
        for(uint64_t i = hash(x); v[i].first != null; i = (i + 1) & ((1 << d) - 1))
            if(v[i].first == x)
                return make_pair(v[i].second, true);
        return make_pair(U(), false);
    }

    bool add(T x, U val){
        if(find(x).second)
            return false;
        if(((q + 1) << 1) > (1 << d) || (1 << d) < 3 * n)
            resize();
        uint64_t i = hash(x);
        for(; v[i].first != null && v[i].first != del; i = (i + 1) & ((1 << d) - 1));
        q += (v[i].first == null);
        ++n;
        v[i] = make_pair(x, val);
        return true;
    }

    bool erase(T x){
        uint64_t i = hash(x);
        for(; v[i].first != null && v[i].first != x; i = (i + 1) & ((1 << d) - 1));
        if(v[i].first == null)
            return false;
        --n;
        v[i] = make_pair(del, U());
        return true;
    }

    void resize(){
        ++d;
        vector<pair<T, U>> old_table;
        q = n;
        swap(old_table, v);
        v.assign(1 << d, make_pair(null, U()));
        n = 0;
        for(int i = 0; i < old_table.size(); ++i)
            if(old_table[i].first != null && old_table[i].first != del)
                add(old_table[i].first, old_table[i].second);
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/avl_map.cpp.html
template <typename T, typename U>
struct AVL_map{
    struct Node{
        int height;
        T key;
        U val;
        Node(T key, U val) : key(key), val(val), height(1){c[0] = 0; c[1] = 0;}
        int c[2];
    };
    vector<Node> nodes;
    stack<int> st;
    AVL_map(){
        nodes.emplace_back(T(), U());
        nodes[0].height = 0;
    }
    template <bool inv>
    int balance_factor(int x){return (nodes[nodes[x].c[0]].height - nodes[nodes[x].c[1]].height) * (inv ? -1 : 1);}
    void _update(int x){
        if(x == 0)
            return;
        nodes[x].height = max(nodes[nodes[x].c[0]].height, nodes[nodes[x].c[1]].height) + 1;
    }
    template <bool is_right>
    int rotate(int x){
        int y = nodes[x].c[1 ^ is_right];
        nodes[x].c[1 ^ is_right] = nodes[y].c[0 ^ is_right];
        nodes[y].c[0 ^ is_right] = x;
        _update(x);
        _update(y);
        return y;
    }
    template <bool inv>
    int _balance(int x){
        if(balance_factor<inv>(x) == 2){
            if(balance_factor<inv>(nodes[x].c[0 ^ inv]) < 0)
                nodes[x].c[0 ^ inv] = rotate<inv>(nodes[x].c[0 ^ inv]);
            x = rotate<1 ^ inv>(x);
        }
        return x;
    }
    int balance(int x){
        x = _balance<false>(x);
        x = _balance<true>(x);
        _update(x);
        return x;
    }
    int add(int x, T key, U val){
        if(x == 0){
            if(st.empty()){
                nodes.emplace_back(key, val);
                return nodes.size() - 1;
            }
            else{
                int y = st.top();
                st.pop();
                nodes[y] = Node(key, val);
                return y;
            }
        }
        else if(key == nodes[x].key)
            nodes[x].val = val;
        else if(key < nodes[x].key)
            nodes[x].c[0] = add(nodes[x].c[0], key, val);
        else
            nodes[x].c[1] = add(nodes[x].c[1], key, val);
        x = balance(x);
        return x;
    }
    // 子が片方しかない時にノードを削除する
    int _erase_top(int x, bool del){
        for(int i = 0; i < 2; ++i){
            if(nodes[x].c[i] == 0){
                int y = nodes[x].c[i ^ 1];
                if(del)
                    st.push(x);
                return y;
            }
        }
        return 0;
    }
    // 最小の要素をdstにコピーしてから削除する
    int _copy_erase(int x, int dst, bool del){
        if(nodes[x].c[0] == 0){
            nodes[dst].val = nodes[x].val;
            return _erase_top(x, del);
        }
        nodes[x].c[0] = _copy_erase(nodes[x].c[0], dst, del);
        x = balance(x);
        return x;
    }
    int erase(int x, T key, bool del = true){
        if(key < nodes[x].key)
            nodes[x].c[0] = erase(nodes[x].c[0], key, del);
        else if(nodes[x].key < key)
            nodes[x].c[1] = erase(nodes[x].c[1], key, del);
        else{
            if(nodes[x].c[0] == 0 || nodes[x].c[1] == 0)
                return _erase_top(x, del);
            nodes[x].c[1] = _copy_erase(nodes[x].c[1], x, del);
        }
        x = balance(x);
        return x;
    }
    pair<U, bool> get(int x, T key){
        if(x == 0)
            return {U(), false};
        else if(key == nodes[x].key)
            return {nodes[x].val, true};
        else if(key < nodes[x].key)
            return get(nodes[x].c[0], key);
        else
            return get(nodes[x].c[1], key);
    }
    vector<pair<T, U>> list(int x){
        vector<pair<T, U>> v;
        stack<pair<int,bool>> sta;
        sta.emplace(x, false);
        bool add;
        while(!sta.empty()){
            tie(x, add) = sta.top();
            sta.pop();
            if(x == 0)
                continue;
            if(add)
                v.emplace_back(nodes[x].key, nodes[x].val);
            else{
                if(nodes[x].c[1])
                    sta.emplace(nodes[x].c[1], false);
                sta.emplace(x, true);
                if(nodes[x].c[0])
                    sta.emplace(nodes[x].c[0], false);
            }
        }
        return v;
    }
};


struct HashPatriciaTree{
    struct Node{
        bool is_elm = false;
        int ch = 0;
        int len = 0;
        int par = -1;
        int data_idx = -1;
        Hash hash;
    };

    static int fat(int l, int r){
        return r & (-1 << (31 - __builtin_clz(l ^ r)));
    };

    AVL_map<int,int> avl;
    vector<function<Hash(int)>> hash_func;
    vector<function<int(int)>> access_func;
    vector<Node> nodes;
    HashMap<uint64_t, int> hmap;
    vector<int> idxes;

    HashPatriciaTree() : nodes(1){
    }

    void make_fat(int x){
        int st = nodes[nodes[x].par].len;
        int en = nodes[x].len;
        int fa = fat(st, en);
        auto ha = hash_func[nodes[x].data_idx](fa);
        nodes[x].hash = ha;
        hmap.add(ha.concat(ha.l).h, x);
    }

    void make(int idx, int target, int len, int label){
        nodes.emplace_back();
        nodes.back().len = len;
        nodes.back().data_idx = idx;
        nodes.back().par = target;
        nodes[target].ch = avl.add(nodes[target].ch, label, nodes.size() - 1);
        make_fat(nodes.size() - 1);
    }

    void split(int idx, int target, int len, int match_len, int new_label, int root_label, int branch_label){
        int par = nodes[target].par;
        nodes.emplace_back();
        nodes.back().len = match_len;
        nodes.back().data_idx = idx;
        nodes.back().par = par;

        Hash ha = nodes[target].hash;
        hmap.erase(ha.concat(ha.l).h);

        nodes[par].ch = avl.add(nodes[par].ch, root_label, nodes.size() - 1);
        nodes.back().ch = avl.add(nodes.back().ch, branch_label, target);
        nodes[target].par = nodes.size() - 1;
        int target_siz = nodes.size() - 1;
        if(nodes.back().len != len)
            make(idx, nodes.size() - 1, len, new_label);
        make_fat(target);
        make_fat(target_siz);
    }

    // f(x): 長さxのprefixのハッシュを返す
    // g(x): x文字目を返す
    void insert(int m, function<Hash(int)> f, function<int(int)> g){
        hash_func.emplace_back(f);
        access_func.emplace_back(g);
        int len, x;
        tie(len, x) = match(m, f, g);
        assert(!(len || x) || (nodes[nodes[x].par].len < len && len <= nodes[x].len));
        if(len == nodes[x].len){
            if(len == m){
                idxes.emplace_back(x);
                nodes[x].data_idx = idxes.size() - 1;
                nodes[x].is_elm = true;
                return;
            }
            else
                make(idxes.size(), x, m, g(len));
        }
        else{
            split(idxes.size(), x, m, len, g(len), access_func[nodes[x].data_idx](nodes[nodes[x].par].len), access_func[nodes[x].data_idx](len));
        }
        idxes.emplace_back(nodes.size() - 1);
        nodes.back().is_elm = true;
    }

    int lcp(int ok, int ng, function<Hash(int)> f, function<Hash(int)> g){
        while(ng - ok > 1){
            int mid = (ok + ng) >> 1;
            (f(mid) == g(mid) ? ok : ng) = mid;
        }
        return ok;
    }

    // (マッチ長, ノード)
    pair<int,int> match(int m, function<Hash(int)> f, function<int(int)> g){
        int ok = 0, ng = m + 1;
        int x = 0;
        int ok_len = 0;
        while(ng - ok > 1){
            int mid = fat(ok + 1, ng - 1);
            Hash h = f(mid);
            int idx;
            bool fl;
            tie(idx, fl) = hmap.find(h.concat(h.l).h);
            if(fl){
                x = idx;
                ok_len = ok;
                ok = nodes[x].len;
            }
            else{
                ng = mid;
            }
        }
        int match_len;
        if(ok == 0){
            match_len = 0;
        }
        else{
            match_len = lcp(ok_len, min(m, nodes[x].len) + 1, f, hash_func[nodes[x].data_idx]);
            if(match_len < nodes[x].len){
                return {match_len, x};
            }
        }
        int label = g(ok);
        int ch;
        bool fl;
        tie(ch, fl) = avl.get(nodes[x].ch, label);
        if(!fl){
            assert(match_len <= m);
            return {match_len, x};
        }
        match_len = lcp(match_len, min(m, nodes[ch].len) + 1, f, hash_func[nodes[ch].data_idx]);
        assert(match_len <= m);
        return {match_len, ch};
    }
    template<typename T>
    static pair<function<Hash(int)>, function<int(int)>> build(T& s, vector<Hash>& v){
        auto f = [&v](int i){
            return v[i];
        };
        auto g = [&s](int i){
            return s[i];
        };
        return {f, g};
    }
    template<typename T>
    static pair<vector<function<Hash(int)>>, vector<function<int(int)>>> build_suffix(T& s, vector<Hash>& v){
        vector<function<Hash(int)>> fv;
        vector<function<int(int)>> gv;
        for(int j = 0; j < s.size(); ++j){
            auto f = [j, &v](int i){
                return v[i + j].sub(v[j]);
            };
            auto g = [j, &s](int i){
                return s[i + j];
            };
            fv.emplace_back(f);
            gv.emplace_back(g);
        }
        return {fv, gv};
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/bitvector.cpp.html
struct BitVector{
    vector<uint64_t> v;
    vector<int> r;
    BitVector(){}
    void build(){
        r.assign(v.size() + 1, 0);
        for(int i = 0; i < v.size(); ++i)
            r[i + 1] = r[i] + __builtin_popcountll(v[i]);
    }
    bool access(int x){
        return (v[x >> 6] >> (x & 63)) & 1;
    }
    // [0, x)の1の出現回数
    int rank(int x){
        return r[x >> 6] + __builtin_popcountll(v[x >> 6] & ((1uLL << (x & 63)) - 1));
    }
    int rank(int x, bool fl){
        return fl ? rank(x) : x - rank(x);
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/waveletmatrix.cpp.html
template <typename T, int W>
struct WaveletMatrix{

    array<BitVector, W> bv;
    array<int, W> zero_cnt;

    WaveletMatrix(vector<T>& a){
        int n = a.size();
        vector<T> v(a);
        for(int i = W - 1; i >= 0; --i){
            vector<uint64_t> b((n >> 6) + 1, 0);
            vector<T> v1, v2;
            for(int j = 0; j < n; ++j){
                ((v[j] >> i) & 1 ? v2 : v1).push_back(v[j]);
                b[j >> 6] |= uint64_t((v[j] >> i) & 1) << (j & 63);
            }
            for(int j = 0; j < v.size(); ++j)
                v[j] = (j < v1.size() ? v1[j] : v2[j - v1.size()]);
            bv[i].v = move(b);
            bv[i].build();
            zero_cnt[i] = bv[i].rank(n, 0);
        }
    }

    // [l, r)内のxの数
    int count(int l, int r, T x){
        for(int i = W - 1; i >= 0; --i){
            bool fl = (x >> i) & 1;
            int st = bv[i].rank(l, fl);
            int en = bv[i].rank(r, fl);
            l = (fl ? zero_cnt[i] : 0) + st;
            r = (fl ? zero_cnt[i] : 0) + en;
        }
        return r - l;
    }

    // [l, r)内で[0, x)を満たす値の数
    int count_lower(int l, int r, T x){
        int cnt = 0;
        for(int i = W - 1; i >= 0; --i){
            bool fl = (x >> i) & 1;
            int st = bv[i].rank(l, fl);
            int en = bv[i].rank(r, fl);
            if(fl){
                st += zero_cnt[i];
                en += zero_cnt[i];
                cnt += (bv[i].rank(r, 0) - bv[i].rank(l, 0));
            }
            l = st, r = en;
        }
        return cnt;
    }

    // [l, r)内で[x, y)を満たす値の数
    int count_range(int l, int r, T x, T y){
        return count_lower(l, r, y) - count_lower(l, r, x);
    }

    // 0-indexedでk番目に小さいものを返す
    T kth_min(int l, int r, int k){
        T ans = 0;
        for(int i = W - 1; i >= 0; --i){
            int st = bv[i].rank(l, 0);
            int en = bv[i].rank(r, 0);
            if(en - st <= k){
                k -= en - st;
                l = zero_cnt[i] + bv[i].rank(l, 1);
                r = zero_cnt[i] + bv[i].rank(r, 1);
                ans |= (1uLL << i);
            }
            else{
                l = st, r = en;
            }
        }
        return ans;
    }

    // [l, r)でのx以上最小値
    pair<T, bool> predecessor(int l, int r, T x){
        int idx = count_lower(l, r, x);
        if(idx == r - l){
            return make_pair((1uLL << W) - 1, false);
        }
        return make_pair(kth_min(l, r, idx), true);
    }

    // [l, r)でのx以下最大値
    pair<T, bool> successor(int l, int r, T x){
        int idx = count_lower(l, r, x + 1);
        if(idx == 0)
            return make_pair(0, false);
        return make_pair(kth_min(l, r, idx - 1), true);
    }
};


signed main(){
    HashPatriciaTree tree;
    string s;
    int q;
    cin >> s >> q;

    int n = s.size();
    vector<Hash> sh = Hash::make(s);
    auto s_res = HashPatriciaTree::build_suffix(s, sh);
    for(int i = 0; i < n; ++i){
        tree.insert(n - i, s_res.first[i], s_res.second[i]);
    }

    vector<int> v;
    int k = tree.nodes.size();
    vector<int> in(k), out(k);
    function<void(int)> f = [&](int x){
        in[x] = v.size();
        v.emplace_back(tree.nodes[x].is_elm ? tree.nodes[x].data_idx : n);
        for(auto p : tree.avl.list(tree.nodes[x].ch)){
            f(p.second);
        }
        out[x] = v.size();
    };
    f(0);

    WaveletMatrix<int, 20> wm(v);

    for(int i = 0; i < q; ++i){
        int l, r;
        string t;
        cin >> l >> r >> t;
        ++r;
        auto h = Hash::make(t);
        auto res = HashPatriciaTree::build(t, h);
        int len, node;
        tie(len, node) = tree.match(t.size(), res.first, res.second);
        if(len < t.size()){
            cout << 0 << endl;
            continue;
        }
        int in_x = in[node];
        int out_x = out[node];

        int left = l;
        int right = max(left, min(int(v.size()), r + 1 - int(t.size())));
        if(right <= left)
            cout << 0 << endl;
        else
            cout << wm.count_range(in_x, out_x, left, right) << endl;
    }
}
accuracy: 1
time_ms: 340
memory_kb: 64384
final_rank: 8

code_snippet: #include <bits/stdc++.h>

using namespace std;

using i64 = int64_t;


// doc: https://shibh308.github.io/library/library/lib/classes/rollinghashmonoid.cpp.html
struct RollingHashMonoid{
    using Hash = RollingHashMonoid;
    using u64 = uint64_t;
    static constexpr u64 mod = (1uLL << 61) - 1;
    static constexpr u64 m30 = (1uLL << 30) - 1;
    static constexpr u64 m31 = (1uLL << 31) - 1;
    static constexpr u64 m61 = mod;
    static constexpr u64 _base = 550390130435464343;
    static constexpr u64 _base_inv = 1803816245541264939;
    static vector<u64> base, base_inv;

    static inline u64 calc_mod(u64 x){
        u64 xu = x >> 61;
        u64 xd = x & m61;
        u64 res = xu + xd;
        if(res >= mod)
            res -= mod;
        return res;
    }

    static inline u64 raw_mul(u64 a, u64 b){
        u64 au = a >> 31;
        u64 ad = a & m31;
        u64 bu = b >> 31;
        u64 bd = b & m31;
        u64 mid = ad * bu + au * bd;
        u64 midu = mid >> 30;
        u64 midd = mid & m30;
        return au * bu * 2 + midu + (midd << 31) + ad * bd;
    }

    static void remake_table(int len){
        while(base.size() <= len){
            base.emplace_back(calc_mod(raw_mul(base.back(), _base)));
            base_inv.emplace_back(calc_mod(raw_mul(base_inv.back(), _base_inv)));
        }
    }

    u64 h, l;

    static inline u64 lshift(u64 a, int len){
        remake_table(len);
        return raw_mul(a, base[len]);
    }
    static inline u64 rshift(u64 a, int len){
        remake_table(len);
        return raw_mul(a, base_inv[len]);
    }

    Hash concat(const Hash& b) const{
        return RollingHashMonoid(
                calc_mod(h + lshift(b.h, l)),
                l + b.l
        );
    }
    Hash sub(const Hash& b) const{
        return RollingHashMonoid(
                calc_mod(rshift(h + mod - b.h, b.l)),
                l - b.l
        );
    }

    RollingHashMonoid() : h(0), l(0){}
    RollingHashMonoid(u64 x) : h(x), l(1){}
    RollingHashMonoid(u64 h, u64 l) : h(h), l(l){}

    friend bool operator==(const Hash& a, const Hash& b){return a.h == b.h && a.l == b.l;}

    template <typename T>
    static vector<Hash> make(vector<T>& x){
        vector<Hash> v(x.size() + 1);
        for(int i = 0; i < x.size(); ++i){
            v[i + 1] = v[i].concat(x[i]);
        }
        return v;
    }
    static vector<Hash> make(string& x){
        vector<Hash> v(x.size() + 1);
        for(int i = 0; i < x.size(); ++i){
            v[i + 1] = v[i].concat(x[i]);
        }
        return v;
    }
};

namespace std{
template<> struct hash<RollingHashMonoid>{
    size_t operator()(const RollingHashMonoid x) const noexcept{
        return x.concat(x.l).h;
    }
};
}


using Hash = RollingHashMonoid;
vector<uint64_t> Hash::base = {1};
vector<uint64_t> Hash::base_inv = {1};


// doc: https://shibh308.github.io/library/library/lib/classes/hashmap.cpp.html
template <typename T, typename U, T del = numeric_limits<T>::max(), T null = numeric_limits<T>::max() - 1>
struct HashMap{
    static constexpr __int128_t z = 0xf332ac987401cba5;
    uint64_t n, q, d;

    vector<pair<T, U>> v;

    HashMap() : n(0), q(0), d(1),  v(2, make_pair(null, U())){
    }

    inline uint64_t hash(T key){return uint64_t((z * __int128_t(key)) >> (64 - d)) & ((1LL << d) - 1);}

    pair<U, bool> find(T x){
        for(uint64_t i = hash(x); v[i].first != null; i = (i + 1) & ((1 << d) - 1))
            if(v[i].first == x)
                return make_pair(v[i].second, true);
        return make_pair(U(), false);
    }

    bool add(T x, U val){
        if(find(x).second)
            return false;
        if(((q + 1) << 1) > (1 << d) || (1 << d) < 3 * n)
            resize();
        uint64_t i = hash(x);
        for(; v[i].first != null && v[i].first != del; i = (i + 1) & ((1 << d) - 1));
        q += (v[i].first == null);
        ++n;
        v[i] = make_pair(x, val);
        return true;
    }

    bool erase(T x){
        uint64_t i = hash(x);
        for(; v[i].first != null && v[i].first != x; i = (i + 1) & ((1 << d) - 1));
        if(v[i].first == null)
            return false;
        --n;
        v[i] = make_pair(del, U());
        return true;
    }

    void resize(){
        ++d;
        vector<pair<T, U>> old_table;
        q = n;
        swap(old_table, v);
        v.assign(1 << d, make_pair(null, U()));
        n = 0;
        for(int i = 0; i < old_table.size(); ++i)
            if(old_table[i].first != null && old_table[i].first != del)
                add(old_table[i].first, old_table[i].second);
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/avl_map.cpp.html
template <typename T, typename U>
struct AVL_map{
    struct Node{
        int height;
        T key;
        U val;
        Node(T key, U val) : key(key), val(val), height(1){c[0] = 0; c[1] = 0;}
        int c[2];
    };
    vector<Node> nodes;
    stack<int> st;
    AVL_map(){
        nodes.emplace_back(T(), U());
        nodes[0].height = 0;
    }
    template <bool inv>
    int balance_factor(int x){return (nodes[nodes[x].c[0]].height - nodes[nodes[x].c[1]].height) * (inv ? -1 : 1);}
    void _update(int x){
        if(x == 0)
            return;
        nodes[x].height = max(nodes[nodes[x].c[0]].height, nodes[nodes[x].c[1]].height) + 1;
    }
    template <bool is_right>
    int rotate(int x){
        int y = nodes[x].c[1 ^ is_right];
        nodes[x].c[1 ^ is_right] = nodes[y].c[0 ^ is_right];
        nodes[y].c[0 ^ is_right] = x;
        _update(x);
        _update(y);
        return y;
    }
    template <bool inv>
    int _balance(int x){
        if(balance_factor<inv>(x) == 2){
            if(balance_factor<inv>(nodes[x].c[0 ^ inv]) < 0)
                nodes[x].c[0 ^ inv] = rotate<inv>(nodes[x].c[0 ^ inv]);
            x = rotate<1 ^ inv>(x);
        }
        return x;
    }
    int balance(int x){
        x = _balance<false>(x);
        x = _balance<true>(x);
        _update(x);
        return x;
    }
    int add(int x, T key, U val){
        if(x == 0){
            if(st.empty()){
                nodes.emplace_back(key, val);
                return nodes.size() - 1;
            }
            else{
                int y = st.top();
                st.pop();
                nodes[y] = Node(key, val);
                return y;
            }
        }
        else if(key == nodes[x].key)
            nodes[x].val = val;
        else if(key < nodes[x].key)
            nodes[x].c[0] = add(nodes[x].c[0], key, val);
        else
            nodes[x].c[1] = add(nodes[x].c[1], key, val);
        x = balance(x);
        return x;
    }
    // 子が片方しかない時にノードを削除する
    int _erase_top(int x, bool del){
        for(int i = 0; i < 2; ++i){
            if(nodes[x].c[i] == 0){
                int y = nodes[x].c[i ^ 1];
                if(del)
                    st.push(x);
                return y;
            }
        }
        return 0;
    }
    // 最小の要素をdstにコピーしてから削除する
    int _copy_erase(int x, int dst, bool del){
        if(nodes[x].c[0] == 0){
            nodes[dst].val = nodes[x].val;
            return _erase_top(x, del);
        }
        nodes[x].c[0] = _copy_erase(nodes[x].c[0], dst, del);
        x = balance(x);
        return x;
    }
    int erase(int x, T key, bool del = true){
        if(key < nodes[x].key)
            nodes[x].c[0] = erase(nodes[x].c[0], key, del);
        else if(nodes[x].key < key)
            nodes[x].c[1] = erase(nodes[x].c[1], key, del);
        else{
            if(nodes[x].c[0] == 0 || nodes[x].c[1] == 0)
                return _erase_top(x, del);
            nodes[x].c[1] = _copy_erase(nodes[x].c[1], x, del);
        }
        x = balance(x);
        return x;
    }
    pair<U, bool> get(int x, T key){
        if(x == 0)
            return {U(), false};
        else if(key == nodes[x].key)
            return {nodes[x].val, true};
        else if(key < nodes[x].key)
            return get(nodes[x].c[0], key);
        else
            return get(nodes[x].c[1], key);
    }
    vector<pair<T, U>> list(int x){
        vector<pair<T, U>> v;
        stack<pair<int,bool>> sta;
        sta.emplace(x, false);
        bool add;
        while(!sta.empty()){
            tie(x, add) = sta.top();
            sta.pop();
            if(x == 0)
                continue;
            if(add)
                v.emplace_back(nodes[x].key, nodes[x].val);
            else{
                if(nodes[x].c[1])
                    sta.emplace(nodes[x].c[1], false);
                sta.emplace(x, true);
                if(nodes[x].c[0])
                    sta.emplace(nodes[x].c[0], false);
            }
        }
        return v;
    }
};


struct HashPatriciaTree{
    struct Node{
        bool is_elm = false;
        int ch = 0;
        int len = 0;
        int par = -1;
        int data_idx = -1;
        Hash hash;
    };

    static int fat(int l, int r){
        return r & (-1 << (31 - __builtin_clz(l ^ r)));
    };

    AVL_map<int,int> avl;
    vector<function<Hash(int)>> hash_func;
    vector<function<int(int)>> access_func;
    vector<Node> nodes;
    HashMap<uint64_t, int> hmap;
    vector<int> idxes;

    HashPatriciaTree() : nodes(1){
    }

    void make_fat(int x){
        int st = nodes[nodes[x].par].len;
        int en = nodes[x].len;
        int fa = fat(st, en);
        auto ha = hash_func[nodes[x].data_idx](fa);
        nodes[x].hash = ha;
        hmap.add(ha.concat(ha.l).h, x);
    }

    void make(int idx, int target, int len, int label){
        nodes.emplace_back();
        nodes.back().len = len;
        nodes.back().data_idx = idx;
        nodes.back().par = target;
        nodes[target].ch = avl.add(nodes[target].ch, label, nodes.size() - 1);
        make_fat(nodes.size() - 1);
    }

    void split(int idx, int target, int len, int match_len, int new_label, int root_label, int branch_label){
        int par = nodes[target].par;
        nodes.emplace_back();
        nodes.back().len = match_len;
        nodes.back().data_idx = idx;
        nodes.back().par = par;

        Hash ha = nodes[target].hash;
        hmap.erase(ha.concat(ha.l).h);

        nodes[par].ch = avl.add(nodes[par].ch, root_label, nodes.size() - 1);
        nodes.back().ch = avl.add(nodes.back().ch, branch_label, target);
        nodes[target].par = nodes.size() - 1;
        int target_siz = nodes.size() - 1;
        if(nodes.back().len != len)
            make(idx, nodes.size() - 1, len, new_label);
        make_fat(target);
        make_fat(target_siz);
    }

    // f(x): 長さxのprefixのハッシュを返す
    // g(x): x文字目を返す
    void insert(int m, function<Hash(int)> f, function<int(int)> g){
        hash_func.emplace_back(f);
        access_func.emplace_back(g);
        int len, x;
        tie(len, x) = match(m, f, g);
        assert(!(len || x) || (nodes[nodes[x].par].len < len && len <= nodes[x].len));
        if(len == nodes[x].len){
            if(len == m){
                idxes.emplace_back(x);
                nodes[x].data_idx = idxes.size() - 1;
                nodes[x].is_elm = true;
                return;
            }
            else
                make(idxes.size(), x, m, g(len));
        }
        else{
            split(idxes.size(), x, m, len, g(len), access_func[nodes[x].data_idx](nodes[nodes[x].par].len), access_func[nodes[x].data_idx](len));
        }
        idxes.emplace_back(nodes.size() - 1);
        nodes.back().is_elm = true;
    }

    int lcp(int ok, int ng, function<Hash(int)> f, function<Hash(int)> g){
        while(ng - ok > 1){
            int mid = (ok + ng) >> 1;
            (f(mid) == g(mid) ? ok : ng) = mid;
        }
        return ok;
    }

    // (マッチ長, ノード)
    pair<int,int> match(int m, function<Hash(int)> f, function<int(int)> g){
        int ok = 0, ng = m + 1;
        int x = 0;
        int ok_len = 0;
        while(ng - ok > 1){
            int mid = fat(ok + 1, ng - 1);
            Hash h = f(mid);
            int idx;
            bool fl;
            tie(idx, fl) = hmap.find(h.concat(h.l).h);
            if(fl){
                x = idx;
                ok_len = ok;
                ok = nodes[x].len;
            }
            else{
                ng = mid;
            }
        }
        int match_len;
        if(ok == 0){
            match_len = 0;
        }
        else{
            match_len = lcp(ok_len, min(m, nodes[x].len) + 1, f, hash_func[nodes[x].data_idx]);
            if(match_len < nodes[x].len){
                return {match_len, x};
            }
        }
        int label = g(ok);
        int ch;
        bool fl;
        tie(ch, fl) = avl.get(nodes[x].ch, label);
        if(!fl){
            assert(match_len <= m);
            return {match_len, x};
        }
        match_len = lcp(match_len, min(m, nodes[ch].len) + 1, f, hash_func[nodes[ch].data_idx]);
        assert(match_len <= m);
        return {match_len, ch};
    }
    template<typename T>
    static pair<function<Hash(int)>, function<int(int)>> build(T& s, vector<Hash>& v){
        auto f = [&v](int i){
            return v[i];
        };
        auto g = [&s](int i){
            return s[i];
        };
        return {f, g};
    }
    template<typename T>
    static pair<vector<function<Hash(int)>>, vector<function<int(int)>>> build_suffix(T& s, vector<Hash>& v){
        vector<function<Hash(int)>> fv;
        vector<function<int(int)>> gv;
        for(int j = 0; j < s.size(); ++j){
            auto f = [j, &v](int i){
                return v[i + j].sub(v[j]);
            };
            auto g = [j, &s](int i){
                return s[i + j];
            };
            fv.emplace_back(f);
            gv.emplace_back(g);
        }
        return {fv, gv};
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/bitvector.cpp.html
struct BitVector{
    vector<uint64_t> v;
    vector<int> r;
    BitVector(){}
    void build(){
        r.assign(v.size() + 1, 0);
        for(int i = 0; i < v.size(); ++i)
            r[i + 1] = r[i] + __builtin_popcountll(v[i]);
    }
    bool access(int x){
        return (v[x >> 6] >> (x & 63)) & 1;
    }
    // [0, x)の1の出現回数
    int rank(int x){
        return r[x >> 6] + __builtin_popcountll(v[x >> 6] & ((1uLL << (x & 63)) - 1));
    }
    int rank(int x, bool fl){
        return fl ? rank(x) : x - rank(x);
    }
};


// doc: https://shibh308.github.io/library/library/lib/classes/waveletmatrix.cpp.html
template <typename T, int W>
struct WaveletMatrix{

    array<BitVector, W> bv;
    array<int, W> zero_cnt;

    WaveletMatrix(vector<T>& a){
        int n = a.size();
        vector<T> v(a);
        for(int i = W - 1; i >= 0; --i){
            vector<uint64_t> b((n >> 6) + 1, 0);
            vector<T> v1, v2;
            for(int j = 0; j < n; ++j){
                ((v[j] >> i) & 1 ? v2 : v1).push_back(v[j]);
                b[j >> 6] |= uint64_t((v[j] >> i) & 1) << (j & 63);
            }
            for(int j = 0; j < v.size(); ++j)
                v[j] = (j < v1.size() ? v1[j] : v2[j - v1.size()]);
            bv[i].v = move(b);
            bv[i].build();
            zero_cnt[i] = bv[i].rank(n, 0);
        }
    }

    // [l, r)内のxの数
    int count(int l, int r, T x){
        for(int i = W - 1; i >= 0; --i){
            bool fl = (x >> i) & 1;
            int st = bv[i].rank(l, fl);
            int en = bv[i].rank(r, fl);
            l = (fl ? zero_cnt[i] : 0) + st;
            r = (fl ? zero_cnt[i] : 0) + en;
        }
        return r - l;
    }

    // [l, r)内で[0, x)を満たす値の数
    int count_lower(int l, int r, T x){
        int cnt = 0;
        for(int i = W - 1; i >= 0; --i){
            bool fl = (x >> i) & 1;
            int st = bv[i].rank(l, fl);
            int en = bv[i].rank(r, fl);
            if(fl){
                st += zero_cnt[i];
                en += zero_cnt[i];
                cnt += (bv[i].rank(r, 0) - bv[i].rank(l, 0));
            }
            l = st, r = en;
        }
        return cnt;
    }

    // [l, r)内で[x, y)を満たす値の数
    int count_range(int l, int r, T x, T y){
        return count_lower(l, r, y) - count_lower(l, r, x);
    }

    // 0-indexedでk番目に小さいものを返す
    T kth_min(int l, int r, int k){
        T ans = 0;
        for(int i = W - 1; i >= 0; --i){
            int st = bv[i].rank(l, 0);
            int en = bv[i].rank(r, 0);
            if(en - st <= k){
                k -= en - st;
                l = zero_cnt[i] + bv[i].rank(l, 1);
                r = zero_cnt[i] + bv[i].rank(r, 1);
                ans |= (1uLL << i);
            }
            else{
                l = st, r = en;
            }
        }
        return ans;
    }

    // [l, r)でのx以上最小値
    pair<T, bool> predecessor(int l, int r, T x){
        int idx = count_lower(l, r, x);
        if(idx == r - l){
            return make_pair((1uLL << W) - 1, false);
        }
        return make_pair(kth_min(l, r, idx), true);
    }

    // [l, r)でのx以下最大値
    pair<T, bool> successor(int l, int r, T x){
        int idx = count_lower(l, r, x + 1);
        if(idx == 0)
            return make_pair(0, false);
        return make_pair(kth_min(l, r, idx - 1), true);
    }
};


signed main(){
    HashPatriciaTree tree;
    string s;
    int q;
    cin >> s >> q;

    int n = s.size();
    vector<Hash> sh = Hash::make(s);
    auto s_res = HashPatriciaTree::build_suffix(s, sh);
    for(int i = 0; i < n; ++i){
        tree.insert(n - i, s_res.first[i], s_res.second[i]);
    }

    vector<int> v;
    int k = tree.nodes.size();
    vector<int> in(k), out(k);
    function<void(int)> f = [&](int x){
        in[x] = v.size();
        v.emplace_back(tree.nodes[x].is_elm ? tree.nodes[x].data_idx : n);
        for(auto p : tree.avl.list(tree.nodes[x].ch)){
            f(p.second);
        }
        out[x] = v.size();
    };
    f(0);

    WaveletMatrix<int, 20> wm(v);

    for(int i = 0; i < q; ++i){
        int l, r;
        string t;
        cin >> l >> r >> t;
        ++r;
        auto h = Hash::make(t);
        auto res = HashPatriciaTree::build(t, h);
        int len, node;
        tie(len, node) = tree.match(t.size(), res.first, res.second);
        if(len < t.size()){
            cout << 0 << endl;
            continue;
        }
        int in_x = in[node];
        int out_x = out[node];

        int left = l;
        int right = max(left, min(int(v.size()), r + 1 - int(t.size())));
        if(right <= left)
            cout << 0 << endl;
        else
            cout << wm.count_range(in_x, out_x, left, right) << endl;
    }
}
accuracy: 1
time_ms: 340
memory_kb: 64168
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout<<#x" = "<<((x))<<endl
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

const int MD = 2;
const ll hash_base[MD] = {1007,1021};
const ll hash_mod[MD] = {1000000009,1000000007};

int N;

const int SZ = 100010;
ll hs[MD][SZ], pw[MD][SZ];
char s[SZ];
char t[SZ];

void init(){
    N = strlen(s);
    rep(i,MD){
        rep(j,N+1){
            hs[i][j] = 0;
            pw[i][j] = 0;
        }

        hs[i][0] = 0;
        pw[i][0] = 1;
        rep(j,N){
            pw[i][j+1] = pw[i][j]*hash_base[i] % hash_mod[i];
            hs[i][j+1] = (hs[i][j]*hash_base[i]+s[j]) % hash_mod[i];
        }
    }
}

// 1-index
ll hash_value(int l, int r, int i){
    return ((hs[i][r] - hs[i][l]*pw[i][r-l])%hash_mod[i]+hash_mod[i])%hash_mod[i];
}

ll calc(int l, int r){
    return (hash_value(l-1,r,0)<<32)|hash_value(l-1,r,1);
}

vector<int> qidx[2000];

int main(){
    int q;
    scanf(" %s %d", t, &q);

    int n = strlen(t);

    vector<int> l(q),r(q);
    vector<int> sz(q);
    vector<ll> qval(q);
    rep(i,q){
        scanf(" %d %d %s", &l[i], &r[i], s);

        sz[i] = strlen(s);
        init();
        qval[i] = calc(1, sz[i]);
    }

    vector<int> usz(sz);
    sort(all(usz));
    usz.erase(unique(all(usz)), usz.end());
    int U = usz.size();

    rep(i,q){
        int idx = lower_bound(all(usz), sz[i]) - usz.begin();
        qidx[idx].pb(i);
    }

    vector<int> ans(q,0);
    strcpy(s,t);
    init();

    assert(U<=500);
    rep(i,U){
        if(usz[i] > n) break;
        unordered_map<ll,vector<int>> pos;
        rep(j,n+1-usz[i]){
            ll hval = calc(j+1, j+usz[i]);
            pos[hval].pb(j);
        }

        for(int j:qidx[i]){
            int L = l[j], R = r[j] - (sz[j]-1);
            if(L>R) continue;
            if(pos.count(qval[j])){
                ans[j] = lower_bound(all(pos[qval[j]]), R+1) - lower_bound(all(pos[qval[j]]), L);
            }
        }
    }

    rep(i,q) printf("%d\n", ans[i]);
    return 0;
}
accuracy: 0.90625
time_ms: 1710
memory_kb: 18336
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout<<#x" = "<<((x))<<endl
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

const int MD = 2;
const ll hash_base[MD] = {1009,1021};
const ll hash_mod[MD] = {1000000009,1000000007};

int N;

const int SZ = 100010;
ll hs[MD][SZ], pw[MD][SZ];
char s[SZ];
char t[SZ];

void init(){
    N = strlen(s);
    rep(i,MD){
        rep(j,N+1){
            hs[i][j] = 0;
            pw[i][j] = 0;
        }

        hs[i][0] = 0;
        pw[i][0] = 1;
        rep(j,N){
            pw[i][j+1] = pw[i][j]*hash_base[i] % hash_mod[i];
            hs[i][j+1] = (hs[i][j]*hash_base[i]+s[j]) % hash_mod[i];
        }
    }
}

// 1-index
ll hash_value(int l, int r, int i){
    return ((hs[i][r] - hs[i][l]*pw[i][r-l])%hash_mod[i]+hash_mod[i])%hash_mod[i];
}

ll calc(int l, int r){
    return (hash_value(l-1,r,0)<<32)|hash_value(l-1,r,1);
}

vector<int> qidx[2000];

int main(){
    int q;
    scanf(" %s %d", t, &q);

    int n = strlen(t);

    vector<int> l(q),r(q);
    vector<int> sz(q);
    vector<ll> qval(q);
    rep(i,q){
        scanf(" %d %d %s", &l[i], &r[i], s);

        sz[i] = strlen(s);
        init();
        qval[i] = calc(1, sz[i]);
    }

    vector<int> usz(sz);
    sort(all(usz));
    usz.erase(unique(all(usz)), usz.end());
    int U = usz.size();

    rep(i,q){
        int idx = lower_bound(all(usz), sz[i]) - usz.begin();
        qidx[idx].pb(i);
    }

    vector<int> ans(q,0);
    strcpy(s,t);
    init();

    assert(U<=500);
    rep(i,U){
        if(usz[i] > n) break;
        unordered_map<ll,vector<int>> pos;
        rep(j,n+1-usz[i]){
            ll hval = calc(j+1, j+usz[i]);
            pos[hval].pb(j);
        }

        for(int j:qidx[i]){
            int L = l[j], R = r[j] - (sz[j]-1);
            if(L>R) continue;
            if(pos.count(qval[j])){
                ans[j] = lower_bound(all(pos[qval[j]]), R+1) - lower_bound(all(pos[qval[j]]), L);
            }
        }
    }

    rep(i,q) printf("%d\n", ans[i]);
    return 0;
}
accuracy: 0.90625
time_ms: 1710
memory_kb: 18332
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout<<#x" = "<<((x))<<endl
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

using pl = pair<int,int>;

struct RollingHash{
    static const int MD = 2;
    static const vector<ll> hash_base, hash_mod;

    int n;
    vector<ll> hs[MD], pw[MD];

    RollingHash(){}
    RollingHash(const string &s){
        n = s.size();
        rep(i,MD){
            hs[i].assign(n+1,0);
            pw[i].assign(n+1,0);
            hs[i][0] = 0;
            pw[i][0] = 1;
            rep(j,n){
                pw[i][j+1] = pw[i][j]*hash_base[i] % hash_mod[i];
                hs[i][j+1] = (hs[i][j]*hash_base[i]+s[j]) % hash_mod[i];
            }
        }
    }

    // 1-index
    ll hash_value(int l, int r, int i){
        return ((hs[i][r] - hs[i][l]*pw[i][r-l])%hash_mod[i]+hash_mod[i])%hash_mod[i];
    }

    bool match(int l1, int r1, int l2, int r2){
        bool ret = true;
        rep(i,MD) ret &= (hash_value(l1-1,r1,i) == hash_value(l2-1,r2,i));
        return ret;
    }

    pl calc(int l, int r){
        // vector<ll> ret(MD);
        // rep(i,MD) ret[i]=hash_value(l-1,r,i);
        // return ret;
        return {hash_value(l-1,r,0), hash_value(l-1,r,1)};
    }
};
const vector<ll> RollingHash::hash_base{1009,1021};
const vector<ll> RollingHash::hash_mod{1000000009,1000000007};

using M = map<pl,int>;
struct SegTree{
    int n; vector<M> dat;
    //初期化
    SegTree(){}
    SegTree(int _n){
        n=1;
        while(n<_n) n*=2;
        dat=vector<M>(2*n-1);
    }

    void add(int k, pl v){
        k+=n-1;
        ++dat[k][v];
        //更新
        while(k>0){
            k=(k-1)/2;
            ++dat[k][v];
        }
    }
    //内部的に投げられるクエリ
    int _query(int a, int b, int k, int l, int r, pl v){
        if(r<=a || b<=l) return 0;
        if(a<=l && r<=b){
            if(dat[k].count(v)) return dat[k][v];
            return 0;
        }

        int vl=_query(a,b,2*k+1,l,(l+r)/2,v);
        int vr=_query(a,b,2*k+2,(l+r)/2,r,v);
        return vl+vr;
    }
    //[a,b)
    int query(int a, int b, pl v){
        return _query(a,b,0,0,n,v);
    }
};


int main(){
    cin.tie(0);ios::sync_with_stdio(false);

    string s;
    int q;
    cin >>s >>q;

    int n = s.size();

    vector<int> l(q),r(q);
    vector<string> m(q);
    vector<int> sz(q);
    rep(i,q){
        cin >>l[i] >>r[i] >>m[i];
        sz[i] = m[i].size();
    }

    vector<int> usz(sz);
    sort(all(usz));
    usz.erase(unique(all(usz)), usz.end());
    int U = usz.size();

    assert(U<=100);

    vector<vector<int>> qidx(U);
    rep(i,q){
        int idx = lower_bound(all(usz), sz[i]) - usz.begin();
        qidx[idx].pb(i);
    }

    vector<int> ans(q);
    RollingHash hs(s);
    rep(i,U){
        if(usz[i]<1000){
            SegTree st(n+1-usz[i]);
            rep(j,n+1-usz[i]) st.add(j, hs.calc(j+1, j+usz[i]));

            for(int j:qidx[i]){
                RollingHash qh(m[j]);
                int L = l[j], R = r[j] - (sz[j]-1);
                ans[j] = st.query(L,R+1,qh.calc(1,sz[j]));
            }
        }
        else{
            for(int j:qidx[i]){
                RollingHash qh(m[j]);
                pl val = qh.calc(1,sz[j]);

                int L = l[j], R = r[j] - (sz[j]-1);
                for(int k=L; k<=R; ++k){
                    if(hs.calc(k+1, k+sz[j]) == val) ++ans[j];
                }
            }
        }
    }

    rep(i,q) cout << ans[i] << "\n";
    return 0;
}
accuracy: 0.359375
time_ms: 20
memory_kb: 3884
final_rank: 20

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


int T_length,P_length,range;
int *Rank; //接尾辞文字列の開始位置iの、辞書順にsortした際の順位表
int *Suffix_Array; //接尾辞文字列の開始位置<インデックス>→毎回、辞書順に開始位置をソートする
int *Work; //作業用配列

char T[100001],P[100001];


//Tのstart文字目から、P_length文字分、Pと比較
//0:等しい 1:Pの方が辞書順で早い 2:Tの方が辞書順で早い
int strCmp_Suffix_Array(int start){
	int index,ret;

	ret = 0;

	for(index = 0; index < P_length && T[start+index] != '\0'; index++){
		if(P[index] != T[start+index]){
			if(P[index] > T[start+index]){ //Tの方が辞書順で早い
				ret = 2;
			}else{
				ret = 1;
			}
			break;
		}
	}
	if(ret == 0 && index < P_length){ //不一致がないまま、Tが先に終わった場合
		ret = 2; //Tの方が辞書順で早い
	}
	return ret;
}


//まずrank[a]とrank[b]を比較、等しければrank[a+range],rank[b+range]を比較
bool compare_Suffix_Array(int a,int b){
	if(Rank[a] != Rank[b])return Rank[a] < Rank[b];
	else{
		int rank_a = a + range <= T_length ? Rank[a+range]:-1; //rangeを足した部分が範囲外なら、最高にするため、rankを-1にする
		int rank_b = b + range <= T_length ? Rank[b+range]:-1;
		return rank_a < rank_b;
	}
}

//文字列Tの接尾辞配列を構築
void make_Suffix_Array(){
	for(int i = 0; i <= T_length; i++){
		Suffix_Array[i] = i;
		Rank[i] = i < T_length? T[i]:-1; //初期ランクは文字コードにする。T[T_length]は空文字なので、最高となるように-1とする
	}

	//range,2*range,4*range,とソート幅を次第に伸ばしていく
	for(range = 1; range <= T_length; range*=2){
		sort(Suffix_Array,Suffix_Array+(T_length+1),compare_Suffix_Array); //range文字の幅でsuffix_Arrayをソート

		Work[Suffix_Array[0]] = 0;
		for(int i = 1; i <= T_length; i++){
			Work[Suffix_Array[i]] = Work[Suffix_Array[i-1]] + (compare_Suffix_Array(Suffix_Array[i-1],Suffix_Array[i])?1:0);
		}
		for(int i = 0; i <= T_length; i++){
			Rank[i] = Work[i];
		}
	}
}


//パターン文字列の、Suffix_Array上での、最も左の一致★インデックス★を返却
int find_match_left(){

	int ret = BIG_NUM;

	int left = 0,right = T_length,m;
	m = (left+right)/2; //suffix_arrayのインデックス

	while(left <= right){
		switch(strCmp_Suffix_Array(Suffix_Array[m])){
		case 0: //T[Suffix_Array[m]～Suffix_Array[m]+P_length]の部分文字列がPと等しい
			ret = m;
			right = m-1; //より左へ
			break;
		case 1: //Pの方が辞書順で早い
			right = m-1;
			break;
		case 2: //Tの方が辞書順で早い
			left = m+1;
			break;
		}
		m = (left+right)/2;
	}
	return ret;
}

//パターン文字列の、Suffix_Array上での、最も右の一致★インデックス★を返却
int find_match_right(){

	int ret = -1;

	int left = 0,right = T_length,m;
	m = (left+right)/2; //suffix_arrayのインデックス

	while(left <= right){
		switch(strCmp_Suffix_Array(Suffix_Array[m])){
		case 0: //T[Suffix_Array[m]～Suffix_Array[m]+P_length]の部分文字列がPと等しい
			ret = max(ret,m);
			left = m+1; //より右へ
			break;
		case 1: //Pの方が辞書順で早い
			right = m-1;
			break;
		case 2: //Tの方が辞書順で早い
			left = m+1;
			break;
		}
		m = (left+right)/2;
	}
	return ret;
}

int count_contain(int left,int right){

	//一番左の一致箇所
	int match_left = find_match_left();
	if(match_left == BIG_NUM)return 0;

	//一番右の一致箇所
	int match_right = find_match_right();
	if(match_right == BIG_NUM)return 0;

	int ret = 0;
	for(int i = match_left; i <= match_right; i++){
		if(Suffix_Array[i] >= left && Suffix_Array[i]+P_length-1 <= right)ret++;
	}
	return ret;
}


int main(){

	int num_query;
	scanf("%s %d",T,&num_query);

	for(T_length = 0; T[T_length] != '\0'; T_length++);

	Rank = new int[T_length+1];
	Suffix_Array = new int[T_length+1];
	Work = new int[T_length+1];

	make_Suffix_Array();

	int left,right;

	for(int loop = 0; loop < num_query; loop++){
		scanf("%d %d %s",&left,&right,P);

		for(P_length = 0; P[P_length] != '\0'; P_length++);

		printf("%d\n",count_contain(left,right));
	}

	return 0;
}
accuracy: 1
time_ms: 540
memory_kb: 4592
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define _MACRO(_1, _2, _3, NAME, ...) NAME
#define _repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define _rep(i,n) _repl(i,0,n)
#define rep(...) _MACRO(__VA_ARGS__, _repl, _rep)(__VA_ARGS__)
#define mp make_pair
#define pb push_back
#define all(x) begin(x),end(x)
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
void _dbg(string){cerr<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cerr<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream &o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream &o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

class SuffixArray {
public:
  string &s;
  vector<int> sa, rank;
  int n;
  void construct_sa(){
    sa.resize(n+1);
    rank.resize(n+1);
    rep(i,n+1){
      sa[i]=i;
      rank[i] = (i<n)?s[i]:(-1);
    }
    vector<int> tmp(n+1,0);
    for(int k=1; k<=n; k*=2){
      auto comp = [&](const int i, const int j){
        if(rank[i]!=rank[j]) return rank[i]<rank[j];
        int ri = (i+k<=n)?(rank[i+k]):-1;
        int rj = (j+k<=n)?(rank[j+k]):-1;
        return ri < rj;
      };
      sort(all(sa), comp);
      tmp[sa[0]]=0;
      rep(i,1,n+1){
        tmp[sa[i]] = tmp[sa[i-1]];
        if(comp(sa[i-1], sa[i])) tmp[sa[i]]++;
      }
      swap(tmp, rank);
    }
  }
  SuffixArray(string &str) : s(str){
    n = s.size();
    construct_sa();
  }
  int getRank(const string t) const {
    int m = t.size();
    int l = 0, r = n+1;
    while(r-l>1){
      int mid = (r+l)/2;
      if(s.compare(sa[mid], m, t) < 0) l = mid;
      else r = mid;
    }
    return r;
  }
};

int rank_v[100005];

class SegTree{
public:
  int n;
  vector<int> data[1<<18];
  SegTree(int n_){
    n=1;
    while(n<n_) n*=2;
    rep(i,n_){
      data[n-1+i].pb(rank_v[i]);
    }
    for(int i=n-2; i>=0; i--){
      int il = 2*i+1, ir = 2*i+2;
      data[i].resize(data[il].size()+data[ir].size());
      merge(all(data[il]), all(data[ir]), data[i].begin());
    }
  }
  // 区間[a,b)でx以下の個数
  int query(int a, int b, int x, int k, int l, int r) const {
    if(r<=a || b<=l) return 0;
    if(a<=l && r<=b){
      return upper_bound(all(data[k]), x) - data[k].begin();
    }
    int vl = query(a,b,x,k*2+1,l,(r+l)/2);
    int vr = query(a,b,x,k*2+2,(r+l)/2,r);
    return vl+vr;
  }
  int query(int a, int b, int x) const {
    return query(a,b,x,0,0,n);
  }
};


int main(){
  ios::sync_with_stdio(false);
  cin.tie(0); cout.tie(0);

  string s;
  int q;
  cin>>s>>q;
  SuffixArray sa(s);
  int n = s.size();

  rep(i,n) rank_v[i] = sa.rank[i];
  SegTree st(s.size());
// dbg(sa.rank, sa.sa);
  rep(_,q){
    int l,r;
    string t;
    cin>>l>>r>>t;
    r = r+1 - (t.size()-1);
    int lb = sa.getRank(t);
    int ub = sa.getRank(t+'|');
    // dbg(lb,ub);

    int ans = st.query(l,r,ub-1) - st.query(l,r,lb-1);
    cout << ans << endl;
  }

  return 0;
}
accuracy: 1
time_ms: 460
memory_kb: 22252
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define _MACRO(_1, _2, _3, NAME, ...) NAME
#define _repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define _rep(i,n) _repl(i,0,n)
#define rep(...) _MACRO(__VA_ARGS__, _repl, _rep)(__VA_ARGS__)
#define mp make_pair
#define pb push_back
#define all(x) begin(x),end(x)
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
void _dbg(string){cerr<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cerr<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream &o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream &o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

class SuffixArray {
public:
  string &s;
  vector<int> sa, rank;
  int n;
  void construct_sa(){
    sa.resize(n+1);
    rank.resize(n+1);
    rep(i,n+1){
      sa[i]=i;
      rank[i] = (i<n)?s[i]:(-1);
    }
    vector<int> tmp(n+1,0);
    for(int k=1; k<=n; k*=2){
      auto comp = [&](const int i, const int j){
        if(rank[i]!=rank[j]) return rank[i]<rank[j];
        int ri = (i+k<=n)?(rank[i+k]):-1;
        int rj = (j+k<=n)?(rank[j+k]):-1;
        return ri < rj;
      };
      sort(all(sa), comp);
      tmp[sa[0]]=0;
      rep(i,1,n+1){
        tmp[sa[i]] = tmp[sa[i-1]];
        if(comp(sa[i-1], sa[i])) tmp[sa[i]]++;
      }
      swap(tmp, rank);
    }
  }
  SuffixArray(string &str) : s(str){
    n = s.size();
    construct_sa();
  }
  int getRank(const string t){
    int m = t.size();
    int l = 0, r = n+1;
    while(r-l>1){
      int mid = (r+l)/2;
      if(s.compare(sa[mid], m, t) < 0) l = mid;
      else r = mid;
    }
    return r;
  }
};

int rank_v[100005];

class SegTree{
public:
  int n;
  vector<int> data[1<<18];
  SegTree(int n_){
    n=1;
    while(n<n_) n*=2;
    rep(i,n_){
      data[n-1+i].pb(rank_v[i]);
    }
    for(int i=n-2; i>=0; i--){
      int il = 2*i+1, ir = 2*i+2;
      data[i].resize(data[il].size()+data[ir].size());
      merge(all(data[il]), all(data[ir]), data[i].begin());
    }
  }
  // 区間[a,b)でx以下の個数
  int query(int a, int b, int x, int k, int l, int r){
    if(r<=a || b<=l) return 0;
    if(a<=l && r<=b){
      return upper_bound(all(data[k]), x) - data[k].begin();
    }
    int vl = query(a,b,x,k*2+1,l,(r+l)/2);
    int vr = query(a,b,x,k*2+2,(r+l)/2,r);
    return vl+vr;
  }
  int query(int a, int b, int x){
    return query(a,b,x,0,0,n);
  }
};


int main(){
  ios::sync_with_stdio(false);
  cin.tie(0); cout.tie(0);

  string s;
  int q;
  cin>>s>>q;
  SuffixArray sa(s);
  int n = s.size();

  rep(i,n) rank_v[i] = sa.rank[i];
  SegTree st(s.size());
// dbg(sa.rank, sa.sa);
  rep(_,q){
    int l,r;
    string t;
    cin>>l>>r>>t;
    r = r+1 - (t.size()-1);
    int lb = sa.getRank(t);
    int ub = sa.getRank(t+'|');
    // dbg(lb,ub);

    int ans = st.query(l,r,ub-1) - st.query(l,r,lb-1);
    cout << ans << endl;
  }

  return 0;
}
accuracy: 1
time_ms: 510
memory_kb: 22328
final_rank: 9

code_snippet: #include<bits/stdc++.h>

using namespace std;

struct SuffixArray
{
  vector< int > SA;
  string s;

  void Build_SA(const string &str)
  {
    s = str;
    SA.resize(s.size());
    iota(begin(SA), end(SA), 0);
    sort(begin(SA), end(SA), [&](const int &a, const int &b)
    {
      if(s[a] == s[b]) return (a > b);
      return (s[a] < s[b]);
    });
    vector< int > classes(s.size()), c(s.size()), cnt(s.size());
    for(int i = 0; i < s.size(); i++) {
      c[i] = s[i];
    }
    for(int len = 1; len < s.size(); len <<= 1) {
      for(int i = 0; i < s.size(); i++) {
        if(i > 0 && c[SA[i - 1]] == c[SA[i]] && SA[i - 1] + len < s.size() && c[SA[i - 1] + len / 2] == c[SA[i] + len / 2]) {
          classes[SA[i]] = classes[SA[i - 1]];
        } else {
          classes[SA[i]] = i;
        }
      }
      iota(begin(cnt), end(cnt), 0);
      copy(begin(SA), end(SA), begin(c));
      for(int i = 0; i < s.size(); i++) {
        int s1 = c[i] - len;
        if(s1 >= 0) SA[cnt[classes[s1]]++] = s1;
      }
      classes.swap(c);
    }
  }

  int operator[](int k) const
  {
    return (SA[k]);
  }

  int size() const
  {
    return (s.size());
  }

  bool lt_substr(string &t, int si = 0, int ti = 0)
  {
    int sn = s.size(), tn = t.size();
    while(si < sn && ti < tn) {
      if(s[si] < t[ti]) return (true);
      if(s[si] > t[ti]) return (false);
      ++si, ++ti;
    }
    return (si >= sn && ti < tn);
  }

  int lower_bound(string &t)
  {
    int low = -1, high = SA.size();
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    return (high);
  }

  pair< int, int > lower_upper_bound(string &t)
  {
    int idx = lower_bound(t);
    int low = idx - 1, high = SA.size();
    t.back()++;
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    t.back()--;
    return (make_pair(idx, high));
  }

  void output()
  {
    for(int i = 0; i < size(); i++) {
      cout << i << ": " << s.substr(SA[i]) << endl;
    }
  }
};

struct SuccinctIndexableDictionary
{
  size_t length;
  size_t blocks;
  vector< unsigned > bit, sum;

  SuccinctIndexableDictionary()
  {
  }

  SuccinctIndexableDictionary(size_t _length)
  {
    length = _length;
    blocks = (length + 31) >> 5;
    bit.assign(blocks, 0U);
    sum.assign(blocks, 0U);
  }

  void set(int k)
  {
    bit[k >> 5] |= 1U << (k & 31);
  }

  void build()
  {
    sum[0] = 0U;
    for(int i = 1; i < blocks; i++) {
      sum[i] = sum[i - 1] + __builtin_popcount(bit[i - 1]);
    }
  }

  bool operator[](int k) const
  {
    return (bool((bit[k >> 5] >> (k & 31)) & 1));
  }

  int rank(int k)
  {
    return (sum[k >> 5] + __builtin_popcount(bit[k >> 5] & ((1U << (k & 31)) - 1)));
  }

  int rank(bool val, int k)
  {
    return (val ? rank(k) : k - rank(k));
  }

  int select(bool val, int k)
  {
    if(k < 0 || rank(val, length) <= k) return (-1);
    int low = 0, high = length;
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(rank(val, mid) >= k + 1) high = mid;
      else low = mid;
    }
    return (high - 1);
  }

  int select(bool val, int i, int l)
  {
    return select(val, i + rank(val, l));
  }
};

template< class T, int MAXLOG >
struct WaveletMatrix
{
  size_t length;
  SuccinctIndexableDictionary matrix[MAXLOG];
  int zs[MAXLOG];
  int buff1[MAXLOG], buff2[MAXLOG];

  void max_dfs(int d, int l, int r, int &k, T val, vector< T > &vs)
  {
    if(l >= r || !k) return;
    if(d == MAXLOG) {
      while(l++ < r && k > 0) vs.push_back(val), k--;
      return;
    }
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    max_dfs(d + 1, lc + zs[d], rc + zs[d], k, 1ULL << (MAXLOG - d - 1) | val, vs);
    max_dfs(d + 1, l - lc, r - rc, k, val, vs);
  }

  T max_dfs(int d, int l, int r, T val, T a, T b)
  {
    if(r - l <= 0 || val >= b) return -1;
    if(d == MAXLOG) return val >= a ? val : -1;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    T ret = max_dfs(d + 1, lc + zs[d], rc + zs[d], 1ULL << (MAXLOG - d - 1) | val, a, b);
    if(~ret) return ret;
    return max_dfs(d + 1, l - lc, r - rc, val, a, b);
  }

  int freq_dfs(int d, int l, int r, T val, T a, T b)
  {
    if(l == r) return 0;
    if(d == MAXLOG) return (a <= val && val < b) ? r - l : 0;
    T nv = 1ULL << (MAXLOG - d - 1) | val, nnv = ((1ULL << (MAXLOG - d - 1)) - 1) | nv;
    if(nnv < a || b <= val) return 0;
    if(a <= val && nnv < b) return r - l;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    return freq_dfs(d + 1, l - lc, r - rc, val, a, b) +
           freq_dfs(d + 1, lc + zs[d], rc + zs[d], nv, a, b);
  }

  void list_dfs(int d, int l, int r, T val, T a, T b, vector< pair< T, int>> &vs)
  {
    if(val >= b || r - l <= 0) return;
    if(d == MAXLOG) {
      if(a <= val) vs.push_back(make_pair(val, r - l));
      return;
    }
    T nv = val | (1LL << (MAXLOG - d - 1)), nnv = nv | (((1LL << (MAXLOG - d - 1)) - 1));
    if(nnv < a) return;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    list_dfs(d + 1, l - lc, r - rc, val, a, b, vs);
    list_dfs(d + 1, lc + zs[d], rc + zs[d], nv, a, b, vs);
  }


  WaveletMatrix(vector< T > data)
  {
    length = data.size();
    vector< T > l(length), r(length);
    for(int depth = 0; depth < MAXLOG; depth++) {
      matrix[depth] = SuccinctIndexableDictionary(length + 1);
      int left = 0, right = 0;
      for(int i = 0; i < length; i++) {
        bool k = (data[i] >> (MAXLOG - depth - 1)) & 1;
        if(k) r[right++] = data[i], matrix[depth].set(i);
        else l[left++] = data[i];
      }
      zs[depth] = left;
      matrix[depth].build();
      swap(l, data);
      for(int i = 0; i < right; i++) data[left + i] = r[i];
    }
  }

  T access(int k)
  {
    int ret = 0;
    bool bit;
    for(int depth = 0; depth < MAXLOG; depth++) {
      bit = matrix[depth][k];
      ret = (ret << 1) | bit;
      k = matrix[depth].rank(bit, k) + zs[depth] * bit;
    }
    return (ret);
  }

  int rank(T val, int k)
  {
    int l = 0, r = k;
    for(int depth = 0; depth < MAXLOG; depth++) {
      buff1[depth] = l, buff2[depth] = r;
      bool bit = (val >> (MAXLOG - depth - 1)) & 1;
      l = matrix[depth].rank(bit, l) + zs[depth] * bit;
      r = matrix[depth].rank(bit, r) + zs[depth] * bit;
    }
    return (r - l);
  }

  int select(T val, int kth)
  {
    rank(val, length);
    for(int depth = MAXLOG - 1; depth >= 0; depth--) {
      bool bit = (val >> (MAXLOG - depth - 1)) & 1;
      kth = matrix[depth].select(bit, kth, buff1[depth]);
      if(kth >= buff2[depth] || kth < 0) return (-1);
      kth -= buff1[depth];
    }
    return (kth);
  }

  int select(T val, int k, int l)
  {
    return (select(val, k + rank(val, l)));
  }


  int quantile(int left, int right, int kth)
  {
    if(right - left <= kth || kth < 0) return (-1);
    T ret = 0;
    for(int depth = 0; depth < MAXLOG; depth++) {
      int l = matrix[depth].rank(1, left);
      int r = matrix[depth].rank(1, right);
      if(r - l > kth) {
        left = l + zs[depth];
        right = r + zs[depth];
        ret |= 1ULL << (MAXLOG - depth - 1);
      } else {
        kth -= r - l;
        left -= l;
        right -= r;
      }
    }
    return (ret);
  }

  vector< T > topk(int l, int r, int k)
  {
    if(r - l < k) k = r - l;
    if(k < 0) return (vector< T >());
    vector< T > ret;
    max_dfs(0, l, r, k, 0, ret);
    return (ret);
  }

  vector< pair< T, int > > freq_list(int l, int r, T a, T b)
  {
    vector< pair< T, int > > ret;
    list_dfs(0, l, r, 0, a, b, ret);
    return (ret);
  }

  vector< pair< int, T > > get_rect(int l, int r, T a, T b)
  {
    vector< pair< T, int > > res = freq_list(l, r, a, b);
    vector< pair< int, T > > ret;
    for(auto &e : res) {
      for(int i = 0; i < e.second; i++) {
        ret.emplace_back(select(e.first, i, l), e.first);
      }
    }
    return (ret);
  }

  int rangefreq(int left, int right, T lower, T upper)
  {
    return (freq_dfs(0, left, right, 0, lower, upper));
  }
};

int main()
{
  char S[100001], T[100001];
  int Q;

  scanf("%s %d", S, &Q);
  SuffixArray sa;
  sa.Build_SA(S);
  vector< int > vs(sa.size());
  for(int i = 0; i < sa.size(); i++) vs[i] = sa[i];
  WaveletMatrix< int, 16 > mat(vs);

  for(int i = 0; i < Q; i++) {
    int l, r;
    scanf("%d %d %s", &l, &r, T);
    string X = T;
    auto p = sa.lower_upper_bound(X);
    printf("%d\n", mat.rangefreq(p.first, p.second, l, r + 1 - (int) X.size() + 1));
  }

}
accuracy: 0.484375
time_ms: 90
memory_kb: 5064
final_rank: 18

code_snippet: #include<bits/stdc++.h>

using namespace std;

struct SuffixArray
{
  vector< int > SA;
  string s;

  void Build_SA(const string &str)
  {
    s = str;
    SA.resize(s.size());
    iota(begin(SA), end(SA), 0);
    sort(begin(SA), end(SA), [&](const int &a, const int &b)
    {
      if(s[a] == s[b]) return (a > b);
      return (s[a] < s[b]);
    });
    vector< int > classes(s.size()), c(s.size()), cnt(s.size());
    for(int i = 0; i < s.size(); i++) {
      c[i] = s[i];
    }
    for(int len = 1; len < s.size(); len <<= 1) {
      for(int i = 0; i < s.size(); i++) {
        if(i > 0 && c[SA[i - 1]] == c[SA[i]] && SA[i - 1] + len < s.size() && c[SA[i - 1] + len / 2] == c[SA[i] + len / 2]) {
          classes[SA[i]] = classes[SA[i - 1]];
        } else {
          classes[SA[i]] = i;
        }
      }
      iota(begin(cnt), end(cnt), 0);
      copy(begin(SA), end(SA), begin(c));
      for(int i = 0; i < s.size(); i++) {
        int s1 = c[i] - len;
        if(s1 >= 0) SA[cnt[classes[s1]]++] = s1;
      }
      classes.swap(c);
    }
  }

  int operator[](int k) const
  {
    return (SA[k]);
  }

  int size() const
  {
    return (s.size());
  }

  bool lt_substr(string &t, int si = 0, int ti = 0)
  {
    int sn = s.size(), tn = t.size();
    while(si < sn && ti < tn) {
      if(s[si] < t[ti]) return (true);
      if(s[si] > t[ti]) return (false);
      ++si, ++ti;
    }
    return (si >= sn && ti < tn);
  }

  int lower_bound(string &t)
  {
    int low = -1, high = SA.size();
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    return (high);
  }

  pair< int, int > lower_upper_bound(string &t)
  {
    int idx = lower_bound(t);
    int low = idx - 1, high = SA.size();
    t.back()++;
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    t.back()--;
    return (make_pair(idx, high));
  }

  void output()
  {
    for(int i = 0; i < size(); i++) {
      cout << i << ": " << s.substr(SA[i]) << endl;
    }
  }
};

struct SuccinctIndexableDictionary
{
  size_t length;
  size_t blocks;
  vector< unsigned > bit, sum;

  SuccinctIndexableDictionary()
  {
  }

  SuccinctIndexableDictionary(size_t _length)
  {
    length = _length;
    blocks = (length + 31) >> 5;
    bit.assign(blocks, 0U);
    sum.assign(blocks, 0U);
  }

  void set(int k)
  {
    bit[k >> 5] |= 1U << (k & 31);
  }

  void build()
  {
    sum[0] = 0U;
    for(int i = 1; i < blocks; i++) {
      sum[i] = sum[i - 1] + __builtin_popcount(bit[i - 1]);
    }
  }

  bool operator[](int k) const
  {
    return (bool((bit[k >> 5] >> (k & 31)) & 1));
  }

  int rank(int k)
  {
    return (sum[k >> 5] + __builtin_popcount(bit[k >> 5] & ((1U << (k & 31)) - 1)));
  }

  int rank(bool val, int k)
  {
    return (val ? rank(k) : k - rank(k));
  }

  int select(bool val, int k)
  {
    if(k < 0 || rank(val, length) <= k) return (-1);
    int low = 0, high = length;
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(rank(val, mid) >= k + 1) high = mid;
      else low = mid;
    }
    return (high - 1);
  }

  int select(bool val, int i, int l)
  {
    return select(val, i + rank(val, l));
  }
};

template< class T, int MAXLOG >
struct WaveletMatrix
{
  size_t length;
  SuccinctIndexableDictionary matrix[MAXLOG];
  int zs[MAXLOG];
  int buff1[MAXLOG], buff2[MAXLOG];

  void max_dfs(int d, int l, int r, int &k, T val, vector< T > &vs)
  {
    if(l >= r || !k) return;
    if(d == MAXLOG) {
      while(l++ < r && k > 0) vs.push_back(val), k--;
      return;
    }
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    max_dfs(d + 1, lc + zs[d], rc + zs[d], k, 1ULL << (MAXLOG - d - 1) | val, vs);
    max_dfs(d + 1, l - lc, r - rc, k, val, vs);
  }

  T max_dfs(int d, int l, int r, T val, T a, T b)
  {
    if(r - l <= 0 || val >= b) return -1;
    if(d == MAXLOG) return val >= a ? val : -1;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    T ret = max_dfs(d + 1, lc + zs[d], rc + zs[d], 1ULL << (MAXLOG - d - 1) | val, a, b);
    if(~ret) return ret;
    return max_dfs(d + 1, l - lc, r - rc, val, a, b);
  }

  int freq_dfs(int d, int l, int r, T val, T a, T b)
  {
    if(l == r) return 0;
    if(d == MAXLOG) return (a <= val && val < b) ? r - l : 0;
    T nv = 1ULL << (MAXLOG - d - 1) | val, nnv = ((1ULL << (MAXLOG - d - 1)) - 1) | nv;
    if(nnv < a || b <= val) return 0;
    if(a <= val && nnv < b) return r - l;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    return freq_dfs(d + 1, l - lc, r - rc, val, a, b) +
           freq_dfs(d + 1, lc + zs[d], rc + zs[d], nv, a, b);
  }

  void list_dfs(int d, int l, int r, T val, T a, T b, vector< pair< T, int>> &vs)
  {
    if(val >= b || r - l <= 0) return;
    if(d == MAXLOG) {
      if(a <= val) vs.push_back(make_pair(val, r - l));
      return;
    }
    T nv = val | (1LL << (MAXLOG - d - 1)), nnv = nv | (((1LL << (MAXLOG - d - 1)) - 1));
    if(nnv < a) return;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    list_dfs(d + 1, l - lc, r - rc, val, a, b, vs);
    list_dfs(d + 1, lc + zs[d], rc + zs[d], nv, a, b, vs);
  }


  WaveletMatrix(vector< T > data)
  {
    length = data.size();
    vector< T > l(length), r(length);
    for(int depth = 0; depth < MAXLOG; depth++) {
      matrix[depth] = SuccinctIndexableDictionary(length + 1);
      int left = 0, right = 0;
      for(int i = 0; i < length; i++) {
        bool k = (data[i] >> (MAXLOG - depth - 1)) & 1;
        if(k) r[right++] = data[i], matrix[depth].set(i);
        else l[left++] = data[i];
      }
      zs[depth] = left;
      matrix[depth].build();
      swap(l, data);
      for(int i = 0; i < right; i++) data[left + i] = r[i];
    }
  }

  T access(int k)
  {
    int ret = 0;
    bool bit;
    for(int depth = 0; depth < MAXLOG; depth++) {
      bit = matrix[depth][k];
      ret = (ret << 1) | bit;
      k = matrix[depth].rank(bit, k) + zs[depth] * bit;
    }
    return (ret);
  }

  int rank(T val, int k)
  {
    int l = 0, r = k;
    for(int depth = 0; depth < MAXLOG; depth++) {
      buff1[depth] = l, buff2[depth] = r;
      bool bit = (val >> (MAXLOG - depth - 1)) & 1;
      l = matrix[depth].rank(bit, l) + zs[depth] * bit;
      r = matrix[depth].rank(bit, r) + zs[depth] * bit;
    }
    return (r - l);
  }

  int select(T val, int kth)
  {
    rank(val, length);
    for(int depth = MAXLOG - 1; depth >= 0; depth--) {
      bool bit = (val >> (MAXLOG - depth - 1)) & 1;
      kth = matrix[depth].select(bit, kth, buff1[depth]);
      if(kth >= buff2[depth] || kth < 0) return (-1);
      kth -= buff1[depth];
    }
    return (kth);
  }

  int select(T val, int k, int l)
  {
    return (select(val, k + rank(val, l)));
  }


  int quantile(int left, int right, int kth)
  {
    if(right - left <= kth || kth < 0) return (-1);
    T ret = 0;
    for(int depth = 0; depth < MAXLOG; depth++) {
      int l = matrix[depth].rank(1, left);
      int r = matrix[depth].rank(1, right);
      if(r - l > kth) {
        left = l + zs[depth];
        right = r + zs[depth];
        ret |= 1ULL << (MAXLOG - depth - 1);
      } else {
        kth -= r - l;
        left -= l;
        right -= r;
      }
    }
    return (ret);
  }

  vector< T > topk(int l, int r, int k)
  {
    if(r - l < k) k = r - l;
    if(k < 0) return (vector< T >());
    vector< T > ret;
    max_dfs(0, l, r, k, 0, ret);
    return (ret);
  }

  vector< pair< T, int > > freq_list(int l, int r, T a, T b)
  {
    vector< pair< T, int > > ret;
    list_dfs(0, l, r, 0, a, b, ret);
    return (ret);
  }

  vector< pair< int, T > > get_rect(int l, int r, T a, T b)
  {
    vector< pair< T, int > > res = freq_list(l, r, a, b);
    vector< pair< int, T > > ret;
    for(auto &e : res) {
      for(int i = 0; i < e.second; i++) {
        ret.emplace_back(select(e.first, i, l), e.first);
      }
    }
    return (ret);
  }

  int rangefreq(int left, int right, T lower, T upper)
  {
    return (freq_dfs(0, left, right, 0, lower, upper));
  }
};

int main()
{
  char S[100001], T[100001];
  int Q;

  scanf("%s %d", S, &Q);
  SuffixArray sa;
  sa.Build_SA(S);
  vector< int > vs(sa.size());
  for(int i = 0; i < sa.size(); i++) vs[i] = sa[i];
  WaveletMatrix< int, 17 > mat(vs);

  for(int i = 0; i < Q; i++) {
    int l, r;
    scanf("%d %d %s", &l, &r, T);
    string X = T;
    auto p = sa.lower_upper_bound(X);
    printf("%d\n", mat.rangefreq(p.first, p.second, l, r + 1 - (int) X.size() + 1));
  }

}
accuracy: 1
time_ms: 170
memory_kb: 5604
final_rank: 1

code_snippet: #include<bits/stdc++.h>

using namespace std;

struct SuffixArray
{
  vector< int > SA;
  string s;

  void Build_SA(const string &str)
  {
    s = str;
    SA.resize(s.size());
    iota(begin(SA), end(SA), 0);
    sort(begin(SA), end(SA), [&](const int &a, const int &b)
    {
      if(s[a] == s[b]) return (a > b);
      return (s[a] < s[b]);
    });
    vector< int > classes(s.size()), c(s.size()), cnt(s.size());
    for(int i = 0; i < s.size(); i++) {
      c[i] = s[i];
    }
    for(int len = 1; len < s.size(); len <<= 1) {
      for(int i = 0; i < s.size(); i++) {
        if(i > 0 && c[SA[i - 1]] == c[SA[i]] && SA[i - 1] + len < s.size() && c[SA[i - 1] + len / 2] == c[SA[i] + len / 2]) {
          classes[SA[i]] = classes[SA[i - 1]];
        } else {
          classes[SA[i]] = i;
        }
      }
      iota(begin(cnt), end(cnt), 0);
      copy(begin(SA), end(SA), begin(c));
      for(int i = 0; i < s.size(); i++) {
        int s1 = c[i] - len;
        if(s1 >= 0) SA[cnt[classes[s1]]++] = s1;
      }
      classes.swap(c);
    }
  }

  int operator[](int k) const
  {
    return (SA[k]);
  }

  int size() const
  {
    return (s.size());
  }

  bool lt_substr(string &t, int si = 0, int ti = 0)
  {
    int sn = s.size(), tn = t.size();
    while(si < sn && ti < tn) {
      if(s[si] < t[ti]) return (true);
      if(s[si] > t[ti]) return (false);
      ++si, ++ti;
    }
    return (si >= sn && ti < tn);
  }

  int lower_bound(string &t)
  {
    int low = -1, high = SA.size();
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    return (high);
  }

  pair< int, int > lower_upper_bound(string &t)
  {
    int idx = lower_bound(t);
    int low = idx - 1, high = SA.size();
    t.back()++;
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    t.back()--;
    return (make_pair(idx, high));
  }

  void output()
  {
    for(int i = 0; i < size(); i++) {
      cout << i << ": " << s.substr(SA[i]) << endl;
    }
  }
};

struct SuccinctIndexableDictionary
{
  size_t length;
  size_t blocks;
  vector< unsigned > bit, sum;

  SuccinctIndexableDictionary()
  {
  }

  SuccinctIndexableDictionary(size_t _length)
  {
    length = _length;
    blocks = (length + 31) >> 5;
    bit.assign(blocks, 0U);
    sum.assign(blocks, 0U);
  }

  void set(int k)
  {
    bit[k >> 5] |= 1U << (k & 31);
  }

  void build()
  {
    sum[0] = 0U;
    for(int i = 1; i < blocks; i++) {
      sum[i] = sum[i - 1] + __builtin_popcount(bit[i - 1]);
    }
  }

  bool operator[](int k) const
  {
    return (bool((bit[k >> 5] >> (k & 31)) & 1));
  }

  int rank(int k)
  {
    return (sum[k >> 5] + __builtin_popcount(bit[k >> 5] & ((1U << (k & 31)) - 1)));
  }

  int rank(bool val, int k)
  {
    return (val ? rank(k) : k - rank(k));
  }

  int select(bool val, int k)
  {
    if(k < 0 || rank(val, length) <= k) return (-1);
    int low = 0, high = length;
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(rank(val, mid) >= k + 1) high = mid;
      else low = mid;
    }
    return (high - 1);
  }

  int select(bool val, int i, int l)
  {
    return select(val, i + rank(val, l));
  }
};

template< class T, int MAXLOG >
struct WaveletMatrix
{
  size_t length;
  SuccinctIndexableDictionary matrix[MAXLOG];
  int zs[MAXLOG];
  int buff1[MAXLOG], buff2[MAXLOG];

  void max_dfs(int d, int l, int r, int &k, T val, vector< T > &vs)
  {
    if(l >= r || !k) return;
    if(d == MAXLOG) {
      while(l++ < r && k > 0) vs.push_back(val), k--;
      return;
    }
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    max_dfs(d + 1, lc + zs[d], rc + zs[d], k, 1ULL << (MAXLOG - d - 1) | val, vs);
    max_dfs(d + 1, l - lc, r - rc, k, val, vs);
  }

  T max_dfs(int d, int l, int r, T val, T a, T b)
  {
    if(r - l <= 0 || val >= b) return -1;
    if(d == MAXLOG) return val >= a ? val : -1;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    T ret = max_dfs(d + 1, lc + zs[d], rc + zs[d], 1ULL << (MAXLOG - d - 1) | val, a, b);
    if(~ret) return ret;
    return max_dfs(d + 1, l - lc, r - rc, val, a, b);
  }

  int freq_dfs(int d, int l, int r, T val, T a, T b)
  {
    if(l == r) return 0;
    if(d == MAXLOG) return (a <= val && val < b) ? r - l : 0;
    T nv = 1ULL << (MAXLOG - d - 1) | val, nnv = ((1ULL << (MAXLOG - d - 1)) - 1) | nv;
    if(nnv < a || b <= val) return 0;
    if(a <= val && nnv < b) return r - l;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    return freq_dfs(d + 1, l - lc, r - rc, val, a, b) +
           freq_dfs(d + 1, lc + zs[d], rc + zs[d], nv, a, b);
  }

  void list_dfs(int d, int l, int r, T val, T a, T b, vector< pair< T, int>> &vs)
  {
    if(val >= b || r - l <= 0) return;
    if(d == MAXLOG) {
      if(a <= val) vs.push_back(make_pair(val, r - l));
      return;
    }
    T nv = val | (1LL << (MAXLOG - d - 1)), nnv = nv | (((1LL << (MAXLOG - d - 1)) - 1));
    if(nnv < a) return;
    int lc = matrix[d].rank(1, l), rc = matrix[d].rank(1, r);
    list_dfs(d + 1, l - lc, r - rc, val, a, b, vs);
    list_dfs(d + 1, lc + zs[d], rc + zs[d], nv, a, b, vs);
  }


  WaveletMatrix(vector< T > data)
  {
    length = data.size();
    vector< T > l(length), r(length);
    for(int depth = 0; depth < MAXLOG; depth++) {
      matrix[depth] = SuccinctIndexableDictionary(length + 1);
      int left = 0, right = 0;
      for(int i = 0; i < length; i++) {
        bool k = (data[i] >> (MAXLOG - depth - 1)) & 1;
        if(k) r[right++] = data[i], matrix[depth].set(i);
        else l[left++] = data[i];
      }
      zs[depth] = left;
      matrix[depth].build();
      swap(l, data);
      for(int i = 0; i < right; i++) data[left + i] = r[i];
    }
  }

  T access(int k)
  {
    int ret = 0;
    bool bit;
    for(int depth = 0; depth < MAXLOG; depth++) {
      bit = matrix[depth][k];
      ret = (ret << 1) | bit;
      k = matrix[depth].rank(bit, k) + zs[depth] * bit;
    }
    return (ret);
  }

  int rank(T val, int k)
  {
    int l = 0, r = k;
    for(int depth = 0; depth < MAXLOG; depth++) {
      buff1[depth] = l, buff2[depth] = r;
      bool bit = (val >> (MAXLOG - depth - 1)) & 1;
      l = matrix[depth].rank(bit, l) + zs[depth] * bit;
      r = matrix[depth].rank(bit, r) + zs[depth] * bit;
    }
    return (r - l);
  }

  int select(T val, int kth)
  {
    rank(val, length);
    for(int depth = MAXLOG - 1; depth >= 0; depth--) {
      bool bit = (val >> (MAXLOG - depth - 1)) & 1;
      kth = matrix[depth].select(bit, kth, buff1[depth]);
      if(kth >= buff2[depth] || kth < 0) return (-1);
      kth -= buff1[depth];
    }
    return (kth);
  }

  int select(T val, int k, int l)
  {
    return (select(val, k + rank(val, l)));
  }


  int quantile(int left, int right, int kth)
  {
    if(right - left <= kth || kth < 0) return (-1);
    T ret = 0;
    for(int depth = 0; depth < MAXLOG; depth++) {
      int l = matrix[depth].rank(1, left);
      int r = matrix[depth].rank(1, right);
      if(r - l > kth) {
        left = l + zs[depth];
        right = r + zs[depth];
        ret |= 1ULL << (MAXLOG - depth - 1);
      } else {
        kth -= r - l;
        left -= l;
        right -= r;
      }
    }
    return (ret);
  }

  vector< T > topk(int l, int r, int k)
  {
    if(r - l < k) k = r - l;
    if(k < 0) return (vector< T >());
    vector< T > ret;
    max_dfs(0, l, r, k, 0, ret);
    return (ret);
  }

  vector< pair< T, int > > freq_list(int l, int r, T a, T b)
  {
    vector< pair< T, int > > ret;
    list_dfs(0, l, r, 0, a, b, ret);
    return (ret);
  }

  vector< pair< int, T > > get_rect(int l, int r, T a, T b)
  {
    vector< pair< T, int > > res = freq_list(l, r, a, b);
    vector< pair< int, T > > ret;
    for(auto &e : res) {
      for(int i = 0; i < e.second; i++) {
        ret.emplace_back(select(e.first, i, l), e.first);
      }
    }
    return (ret);
  }

  int rangefreq(int left, int right, T lower, T upper)
  {
    return (freq_dfs(0, left, right, 0, lower, upper));
  }
};

int main()
{
  char S[100001], T[100001];
  int Q;

  scanf("%s %d", S, &Q);
  SuffixArray sa;
  sa.Build_SA(S);
  vector< int > vs(sa.size());
  for(int i = 0; i < sa.size(); i++) vs[i] = sa[i];
  WaveletMatrix< int, 18 > mat(vs);

  for(int i = 0; i < Q; i++) {
    int l, r;
    scanf("%d %d %s", &l, &r, T);
    string X = T;
    auto p = sa.lower_upper_bound(X);
    printf("%d\n", mat.rangefreq(p.first, p.second, l, r + 1 - (int) X.size() + 1));
  }

}
accuracy: 1
time_ms: 190
memory_kb: 5588
final_rank: 2

code_snippet: #include<bits/stdc++.h>

#define rep(i,n) for(int i=0;i<(int)n;i++)
#define all(c) (c).begin(),(c).end()
#define mp make_pair
#define pb push_back
#define each(i,c) for(__typeof((c).begin()) i=(c).begin();i!=(c).end();i++)
#define dbg(x) cerr<<__LINE__<<": "<<#x<<" = "<<(x)<<endl

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
const int inf = (int)1e9;
const double INF = 1e12, EPS = 1e-9;

const int MAX_LEN = 2500000;
int si[MAX_LEN], is[MAX_LEN], lcp[MAX_LEN];

void buildSA(const char *t){
	static int a[MAX_LEN], b[MAX_LEN];
	static pair<int, int> p[MAX_LEN];
	
	int n = strlen(t);
	
	rep(i, n + 1) is[i] = t[i], p[i] = make_pair(is[i], i);
	sort(p, p + n + 1);
	rep(i, n + 1) si[i] = p[i].second;
	
	for(int h = 0; ; ){
		rep(i, n){
			int x = si[i + 1], y = si[i];
			b[i + 1] = b[i];
			if(is[x] > is[y] || is[x + h] > is[y + h]) b[i + 1]++;
		}
		rep(i, n + 1) is[si[i]] = b[i];
		if(b[n] == n) break;
		h = max(1, h << 1);
		
		for(int k = h; k >= 0; k -= h){
			rep(i, n + 1) b[i] = 0;
			b[0] = k;
			
			for(int i = k; i <= n; i++) b[is[i]]++;
			rep(i, n) b[i + 1] += b[i];
			for(int i = n; i >= 0; i--)
				a[--b[si[i] + k > n ? 0 : is[si[i] + k]]] = si[i];
			
			swap(si, a);
		}
	}
}
void buildLCP(const char *t){
	int h = 0, n = strlen(t);
	
	rep(i, n + 1){
		if(is[i]){
			for(int j = si[is[i] - 1];
				j + h < n && i + h < n && t[j + h] == t[i + h]; h++);
			lcp[is[i]] = h;
		}
		else lcp[is[i]] = -1;
		if(h > 0) h--;
	}
}

//n?????????????????????+1
int *buildRMQ(int *a, int n){
	int logn = 1;
	for (int k = 1; k < n; k *= 2) ++logn;
	int *r = new int[n * logn];
	int *b = r;
	copy(a, a+n, b);
	for (int k = 1; k < n; k *= 2){
		copy(b, b + n, b + n); b += n;
		rep(i, n - k) b[i] = min(b[i], b[i+k]);
	}
	return r;
}
inline int minimum(int x, int y, int *rmq, int n){
	if(y <= x) return inf;
	if(x + 1 == y) return rmq[x];
	int z = --y - x, k = 31 - __builtin_clz(z);
	return min( rmq[x + n * k], rmq[y + n * k - (1 << k) + 1] );
}
int q, l[100000], r[100000];

struct RangeTree{
	vector<vi> dat;
	int n;
	RangeTree(int *a, int size){
		for(n = 1; n < size; n *= 2);
		dat.resize(2 * n - 1);
		init(a, size);
	}
	void init(int *a, int size){
		rep(i, size) dat[i + n - 1].pb(a[i]);
		for(int i = n - 2; i >= 0; i--){
			dat[i].resize(dat[i * 2 + 1].size() + dat[i * 2 + 2].size());
			merge(all(dat[i * 2 + 1]), all(dat[i * 2 + 2]), dat[i].begin());
		}
	}
	int query(int a, int b, int k, int l, int r, int v, int V){
		if(r <= a || b <= l) return 0;
		if(a <= l && r <= b) return lower_bound(all(dat[k]), V) - lower_bound(all(dat[k]), v);
		int vl = query(a, b, k * 2 + 1, l, (l + r) / 2, v, V);
		int vr = query(a, b, k * 2 + 2, (l + r) / 2, r, v, V);
		return vl + vr;
	}
	//[a, b)????????????[v, V)????????°
	int query(int a, int b, int v, int V){ return query(a, b, 0, 0, n, v, V); }
};

int main(){
	cin.tie(0); cin.sync_with_stdio(0);
	vi pos, len;
	string s;
	cin >> s >> q;
	rep(i, q){
		string m; cin >> l[i] >> r[i] >> m; r[i]++;
		s += '$'; pos.pb(s.size());
		s += m;   len.pb(m.size());
	}
	//dbg(s);
	//rep(i, q) dbg(s.substr(pos[i]));
	
	int n = s.size();
	buildSA(s.c_str());
	buildLCP(s.c_str());
	int *rmq = buildRMQ(lcp, n + 1);
	
	RangeTree S(si, n + 1);
	
	rep(i, q){
		int idx = is[pos[i]]; assert(si[idx] == pos[i]);
		int lo = 0, hi = idx, mid, L, R;
		while(lo + 1 < hi){
			mid = (lo + hi) / 2;
			if(minimum(mid + 1, idx + 1, rmq, n + 1) < len[i]) lo = mid;
			else hi = mid;
		}
		L = hi;
		
		lo = idx; hi = n + 1;
		while(lo + 1 < hi){
			mid = (lo + hi) / 2;
			if(minimum(idx + 1, mid + 1, rmq, n + 1) < len[i]) hi = mid;
			else lo = mid;
		}
		R = hi;
		
		//cerr<<"idx: "<<idx<<" L: "<<L<<" R: "<<R<<" min:"<<l[i]<<" max: "<<r[i] - len[i]+1<<endl;
		
		printf("%d\n", S.query(L, R, l[i], r[i] - len[i] + 1));
	}
	
	//rep(i, n+1)cerr<<i<<" "<<lcp[i]<<" "<<si[i]<<" "<<(i<=n?s.substr(si[i]):"")<<endl;
	
	return 0;
}
accuracy: 1
time_ms: 1220
memory_kb: 422256
final_rank: 12

code_snippet: #include<bits/stdc++.h>

#define rep(i,n) for(int i=0;i<(int)n;i++)
#define all(c) (c).begin(),(c).end()
#define mp make_pair
#define pb push_back
#define each(i,c) for(__typeof((c).begin()) i=(c).begin();i!=(c).end();i++)
#define dbg(x) cerr<<__LINE__<<": "<<#x<<" = "<<(x)<<endl

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
const int inf = (int)1e9;
const double INF = 1e12, EPS = 1e-9;

const int MAX_LEN = 2500000;
int si[MAX_LEN], is[MAX_LEN], lcp[MAX_LEN];

void buildSA(char *t){
	static int a[MAX_LEN], b[MAX_LEN];
	static pair<int, int> p[MAX_LEN];
	
	int n = strlen(t);
	
	rep(i, n + 1) is[i] = t[i], p[i] = make_pair(is[i], i);
	sort(p, p + n + 1);
	rep(i, n + 1) si[i] = p[i].second;
	
	for(int h = 0; ; ){
		rep(i, n){
			int x = si[i + 1], y = si[i];
			b[i + 1] = b[i];
			if(is[x] > is[y] || is[x + h] > is[y + h]) b[i + 1]++;
		}
		rep(i, n + 1) is[si[i]] = b[i];
		if(b[n] == n) break;
		h = max(1, h << 1);
		
		for(int k = h; k >= 0; k -= h){
			rep(i, n + 1) b[i] = 0;
			b[0] = k;
			
			for(int i = k; i <= n; i++) b[is[i]]++;
			rep(i, n) b[i + 1] += b[i];
			for(int i = n; i >= 0; i--)
				a[--b[si[i] + k > n ? 0 : is[si[i] + k]]] = si[i];
			
			swap(si, a);
		}
	}
}
void buildLCP(char *t){
	int h = 0, n = strlen(t);
	
	rep(i, n + 1){
		if(is[i]){
			for(int j = si[is[i] - 1];
				j + h < n && i + h < n && t[j + h] == t[i + h]; h++);
			lcp[is[i]] = h;
		}
		else lcp[is[i]] = -1;
		if(h > 0) h--;
	}
}

//n?????????????????????+1
int *buildRMQ(int *a, int n){
	int logn = 1;
	for (int k = 1; k < n; k *= 2) ++logn;
	int *r = new int[n * logn];
	int *b = r;
	copy(a, a+n, b);
	for (int k = 1; k < n; k *= 2){
		copy(b, b + n, b + n); b += n;
		rep(i, n - k) b[i] = min(b[i], b[i+k]);
	}
	return r;
}
inline int minimum(int x, int y, int *rmq, int n){
	if(--y < x) return inf;
	if(x == y) return rmq[x];
	int z = y - x, k = 31 - __builtin_clz(z);
	return min( rmq[x + n * k], rmq[y + n * k - (1 << k) + 1] );
}

char s[MAX_LEN];
int q, l[100000], r[100000], pos[100000];

template<class T>struct SegTree{
	T *dat;
	int n;
	SegTree(int size, int *a){
		for(n = 1; n < size; n *= 2);
		dat = new T[2 * n - 1];
		init(size, a);
	}
	~SegTree(){ delete [] dat; }
	
	void init(int sz, int *a){
		rep(i, sz) dat[i + n - 1].pb(a[i]);
		for(int i = n - 2; i >= 0; i--){
			dat[i].resize(dat[i * 2 + 1].size() + dat[i * 2 + 2].size());
			merge(all(dat[i * 2 + 1]), all(dat[i * 2 + 2]), dat[i].begin());
		}
	}
	int query(int a, int b, int k, int l, int r, int v, int V){
		if(r <= a || b <= l) return 0;
		if(a <= l && r <= b) return lower_bound(all(dat[k]), V) - lower_bound(all(dat[k]), v);
		int vl = query(a, b, k * 2 + 1, l, (l + r) / 2, v, V);
		int vr = query(a, b, k * 2 + 2, (l + r) / 2, r, v, V);
		return vl + vr;
	}
	int query(int a, int b, int v, int V){ return query(a, b, 0, 0, n, v, V); }
};

int main(){
	scanf("%s%d", s, &q);
	int p = strlen(s); s[p++] = '$';
	rep(i, q){
		scanf("%d%d%s", l + i, r + i, s + (pos[i] = p)); r[i]++;
		p += strlen(s + pos[i]);
		s[p++] = '$';
	}
	pos[q] = p;
	buildSA(s);
	buildLCP(s);
	int *rmq = buildRMQ(lcp, p + 1);
	SegTree<vi> S(p + 1, si);
	
	rep(it, q){
		int idx = is[pos[it]], len = pos[it + 1] - pos[it] - 1;
		int lo = 0, hi = idx, mid, L, R;
		
		while(lo + 1 < hi){
			mid = (lo + hi) / 2;
			if(minimum(mid + 1, idx + 1, rmq, p + 1) < len) lo = mid;
			else hi = mid;
		}
		L = hi; lo = idx; hi = p + 1;
		while(lo + 1 < hi){
			mid = (lo + hi) / 2;
			if(minimum(idx + 1, mid + 1, rmq, p + 1) < len) hi = mid;
			else lo = mid;
		}
		R = hi;
		
		//cerr<<"L: "<<L<<" R: "<<R<<" lit: "<<l[it]<<" rit: "<<r[it]<<" len: "<<len<<"    idx: "<<idx<<endl;
		
		printf("%d\n", S.query(L, R, l[it], r[it] - len + 1));
	}
	//rep(i, p + 1) cerr<<i<<" "<<lcp[i]<<" "<<si[i]<<" "<<s + si[i]<<endl;
	
	return 0;
}
accuracy: 0.671875
time_ms: 1140
memory_kb: 421284
final_rank: 15

code_snippet: #include<bits/stdc++.h>

#define rep(i,n) for(int i=0;i<(int)n;i++)
#define all(c) (c).begin(),(c).end()
#define mp make_pair
#define pb push_back
#define each(i,c) for(__typeof((c).begin()) i=(c).begin();i!=(c).end();i++)
#define dbg(x) cerr<<__LINE__<<": "<<#x<<" = "<<(x)<<endl

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
const int inf = (int)1e9;
const double INF = 1e12, EPS = 1e-9;

const int MAX_LEN = 2500000;
int si[MAX_LEN], is[MAX_LEN], lcp[MAX_LEN];

void buildSA(char *t){
	static int a[MAX_LEN], b[MAX_LEN];
	static pair<int, int> p[MAX_LEN];
	
	int n = strlen(t);
	
	rep(i, n + 1) is[i] = t[i], p[i] = make_pair(is[i], i);
	sort(p, p + n + 1);
	rep(i, n + 1) si[i] = p[i].second;
	
	for(int h = 0; ; ){
		rep(i, n){
			int x = si[i + 1], y = si[i];
			b[i + 1] = b[i];
			if(is[x] > is[y] || is[x + h] > is[y + h]) b[i + 1]++;
		}
		rep(i, n + 1) is[si[i]] = b[i];
		if(b[n] == n) break;
		h = max(1, h << 1);
		
		for(int k = h; k >= 0; k -= h){
			rep(i, n + 1) b[i] = 0;
			b[0] = k;
			
			for(int i = k; i <= n; i++) b[is[i]]++;
			rep(i, n) b[i + 1] += b[i];
			for(int i = n; i >= 0; i--)
				a[--b[si[i] + k > n ? 0 : is[si[i] + k]]] = si[i];
			
			swap(si, a);
		}
	}
}
void buildLCP(char *t){
	int h = 0, n = strlen(t);
	
	rep(i, n + 1){
		if(is[i]){
			for(int j = si[is[i] - 1];
				j + h < n && i + h < n && t[j + h] == t[i + h]; h++);
			lcp[is[i]] = h;
		}
		else lcp[is[i]] = -1;
		if(h > 0) h--;
	}
}

//n?????????????????????+1
int *buildRMQ(int *a, int n){
	int logn = 1;
	for (int k = 1; k < n; k *= 2) ++logn;
	int *r = new int[n * logn];
	int *b = r;
	copy(a, a+n, b);
	for (int k = 1; k < n; k *= 2){
		copy(b, b + n, b + n); b += n;
		rep(i, n - k) b[i] = min(b[i], b[i+k]);
	}
	return r;
}
inline int minimum(int x, int y, int *rmq, int n){
	if(--y < x) return inf;
	if(x == y) return rmq[x];
	int z = y - x, k = 31 - __builtin_clz(z);
	return min( rmq[x + n * k], rmq[y + n * k - (1 << k) + 1] );
}

char s[MAX_LEN];
int q, l[100000], r[100000], pos[100000];

template<class T>struct SegTree{
	T *dat;
	int n;
	SegTree(int size, int *a){
		for(n = 1; n < size; n *= 2);
		dat = new T[2 * n - 1];
		init(size, a);
	}
	~SegTree(){ delete [] dat; }
	
	void init(int sz, int *a){
		rep(i, sz) dat[i + n - 1].pb(a[i]);
		for(int i = n - 2; i >= 0; i--){
			dat[i].resize(dat[i * 2 + 1].size() + dat[i * 2 + 2].size());
			merge(all(dat[i * 2 + 1]), all(dat[i * 2 + 2]), dat[i].begin());
		}
	}
	int query(int a, int b, int k, int l, int r, int v, int V){
		if(r <= a || b <= l) return 0;
		if(a <= l && r <= b) return lower_bound(all(dat[k]), V) - lower_bound(all(dat[k]), v);
		int vl = query(a, b, k * 2 + 1, l, (l + r) / 2, v, V);
		int vr = query(a, b, k * 2 + 2, (l + r) / 2, r, v, V);
		return vl + vr;
	}
	int query(int a, int b, int v, int V){ return query(a, b, 0, 0, n, v, V); }
};

int main(){
	scanf("%s%d", s, &q);
	int p = strlen(s); s[p++] = '$';
	rep(i, q){
		scanf("%d%d%s", l + i, r + i, s + (pos[i] = p)); r[i]++;
		p += strlen(s + pos[i]);
		s[p++] = '$';
	}
	pos[q] = p;
	buildSA(s);
	buildLCP(s);
	int *rmq = buildRMQ(lcp, p + 1);
	SegTree<vi> S(p + 1, si);
	
	rep(it, q){
		int idx = is[pos[it]], len = pos[it + 1] - pos[it] - 1;
		int lo = -1, hi = idx, mid, L, R;
		
		while(lo + 1 < hi){
			mid = (lo + hi) / 2;
			if(minimum(mid + 1, idx + 1, rmq, p + 1) < len) lo = mid;
			else hi = mid;
		}
		L = hi; lo = idx; hi = p + 1;
		while(lo + 1 < hi){
			mid = (lo + hi) / 2;
			if(minimum(idx + 1, mid + 1, rmq, p + 1) < len) hi = mid;
			else lo = mid;
		}
		R = hi;
		
		//cerr<<"L: "<<L<<" R: "<<R<<" lit: "<<l[it]<<" rit: "<<r[it]<<" len: "<<len<<"    idx: "<<idx<<endl;
		
		printf("%d\n", S.query(L, R, l[it], r[it] - len + 1));
	}
	//rep(i, p + 1) cerr<<i<<" "<<lcp[i]<<" "<<si[i]<<" "<<s + si[i]<<endl;
	
	return 0;
}
accuracy: 0.671875
time_ms: 1160
memory_kb: 421296
final_rank: 16