Question is intended: to give you a string of length n, there are m times asked each time to the position of the substring interrogation l r occurring in the k-th original string, -1 if no output. n, m are 1e5 level.
Ideas: regret not learn suffix array QAQ, in fact, as long as the suffix array learned this question quite a miss. This problem can be converted into the number of suffixes and suffix lcp length l is greater than or equal r - l + 1. We know that, in the suffix array, two suffixes i, j is the lcp min (height [rank [j] + 1], height [rank [j] + 2], .... height [rank [i]] ). So, we can separate the two left most position (assuming that this position is p), the position to the rank [l] is the height> = r - l + 1, i.e. from p to rank [l] these locations suffix and lcp is greater than or equal length l r - l + 1 is. The right rank [l] can be obtained in the same way. So, we can know what suffix may be the answer. Then there is a problem, how do you know they are in the k-th position it? This is a big problem k-static range, we sa [i] in order to insert Chairman tree, and then ask the k-large positions can be dichotomized between two endpoints separated.
Code (suffix array board copy online QAQ):
#include <bits / STDC ++ H.> the using namespace STD; const int MAXN = 100010; char S [MAXN]; int n-, TOT; int the root [MAXN]; struct Node { int SUM; int LC, RC; }; Node TR [MAXN * 50]; struct SA { int SA [MAXN], X [MAXN], Y [MAXN], C [MAXN]; int Rank [MAXN], height [MAXN], H [MAXN]; int F [ MAXN] [18 is]; void build_sa (int m) { for (int I = 0; I <= m; I ++) C [I] = 0; for (int I =. 1; I <= n-; ++ I) C ++ [X [i] = S [i]]; // C is the array tub // x [i] is the i-th element of the first key for (int i = 2; i <= m; + i +) c [i] + = c [i-1]; // prefix and c do, we can draw up to each keyword is the first of several for (int I = n-; I> =. 1; Inc. (www.i-levelmedia.com)) SA [C [X [I]] -] = I; for (int i = 2; i <= m; ++ i) c [i] + = c [i- 1]; // first keyword ranking 1 to the number of how many i for (int. 1 = K; K <= n-; = K <<. 1) { int NUM = 0; for (int I = n-K-+. 1; I <= n-; I ++) Y [NUM ++] i =; // Y [i] represents a second keyword ranking number i, the position of the first keyword // n-k + 1 of the n-th bit to the second keyword is therefore not in the front rank for (int i =. 1; i <= n-; i ++) iF (SA [i]> K) Y [NUM ++] = SA [i] -k; // rank i is the number in the array in the k-th bit after // If the condition (sa [i]> k) then it may be used as the second key others, which put the first keyword position on the line y add // so enumeration i is the second key, the second key to the front enqueued for (int i =. 1; I <= m; I ++) c [I] = 0; // initialize c tub for (int i . 1 =; <= n-I; I ++) ++ C [X [I]]; // because the last time the cycle has been calculated so that the first keyword directly added on the list // y is because the order of the second keyword according to order row after // second keyword rearward, in the same first keyword ranked by the bucket for (int I = n-; I> =. 1; Inc. (www.i-levelmedia.com)) SA [C [X [Y [I]]] -] = Y [I], Y [I] = 0; for (int I =. 1; I <= n-; I ++) { // radix sort swap (x, the y-); // here do not think too much, because you want to use to generate the old, put the old copy down when the new x, no other meaning x [sa [1]] . 1 =; NUM =. 1; for (int I = 2; I <= n-; I ++) X [SA [I]] = (Y [SA [I]] == Y [SA [-I. 1]] the y-&& [sa [i] + k] the y-== [SA [i-1] + k]) NUM:? NUM ++; // because sa [i] is already sorted, so you can enumerate by rating , generating a first key under the IF (== n-NUM) BREAK; m = NUM; // here that not 122, because there are a number of new } } void get_height () { int K = 0; for (int I =. 1; I <= n-; I ++) Rank [SA [I]] = I; IF (Rank [I] ==. 1) Continue; // first height is 0 IF (K) - K; // H [I]> = H [. 1-I] -1; int J = SA [Rank [I] -1]; while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k; height[rank[i]]=k;//h[i]=height[rk[i]]; } for (int i = 1; i <= n; i++) h[i] = height[rank[i]]; } void build_st() { for (int i = 1; i <= n; i++) f[i][0] = height[i]; int t = log(n) / log(2) + 1; for (int j = 1; j < t; j++) { for (int i = 1; i <= n - (1 << j) + 1; i++) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); } } int query(int l, int r) { if(l > r) return 0; int k = log(r - l + 1) / log(2); return min(f[l][k], f[r - (1 <<k) + 1] [k]); } }; SA solve; int build(int l, int r) { int p = ++tot; if (l == r) { tr[p].sum = 0; tr[p].lc = tr[p].rc = 0; return p; } int mid = (l + r) >> 1; tr[p].lc = build(l, mid); tr[p].rc = build(mid + 1, r); tr[p].sum = tr[tr[p].lc].sum + tr[tr[p].rc].sum; return p; } int insert(int now, int l, int r, int x, int val) { int p = ++tot; tr[p] = tr[now]; if(l == r) { tr[p].sum = 1; return p; } int mid = (l + r) >> 1; if(x <= mid) tr[p].lc = insert(tr[now].lc, l, mid, x, val); else tr[p].rc = insert(tr[now].rc, mid + 1, r, x, val); tr[p].sum = tr[tr[p].lc].sum + tr[tr[p].rc].sum; return p; } int query(int lnow, int rnow, int l, int r, int remain) { if(l > r) return 0; if(l == r) { return l; } int mid = (l + r) >> 1; int tmp = tr[tr[rnow].lc].sum - tr[tr[lnow].lc].sum; if(tmp >= remain) return query(tr[lnow].lc, tr[rnow].lc, l, mid, remain); else return query(tr[lnow].rc, tr[rnow].rc, mid + 1, r, remain - tmp); } int main() { int T, m, l, r, k, ql, qr; // freopen("cin.txt", "r", stdin); // freopen("cout.txt", "w", stdout); scanf("%d", &T); while(T--) { tot = 0; scanf("%d%d", &n, &m); scanf("%s", s + 1); for (int i = 1; i <= n; i++) s[i] -= ('a' - 1); solve.build_sa(30); solve.get_height(); solve.build_st(); root[0] = build(1, n); for (int i = 1; i <= n; i++) { root[i] = insert(root[i - 1], 1, n, solve.sa[i], 1); } for (int i = 1; i <= m; i++) { scanf("%d%d%d", &l, &r, &k); int p = solve.rank[l]; int L = 1, R = p; while(L < R) { int mid = (L + R) >> 1; if(solve.query(mid + 1, p) < r - l + 1) L = mid + 1; else R = mid; } ql = L; L = p, R = n; while(L < R) { int mid = (L + R + 1) >> 1; if(solve.query(p + 1, mid) < r - l + 1) R = mid - 1; else L = mid; } qr = R; if(qr - ql + 1 < k) printf("-1\n"); else printf("%d\n", query(root[ql - 1], root[qr], 1, n, k)); } } }