题意:给一个长度为n的字符串s,然后有q个询问,每次询问求出l到r之间的字串在s数组第k次出现的位置;
思路:用后缀数组对所有子串进行排序,用二分和RMQ找到包含该子串的排名区间(含公共前缀的字串一定连续,二分左边界和右边界),用权值主席树查找第k次出现的子串的位置即可;
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<string>
#include<cstring>
#include<bitset>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<iomanip>
#include<algorithm>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl "\n"
#define PI acos(-1)
//CLOCKS_PER_SEC clock()函数每秒执行次数
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e5+5;
int mod = 1e9 +7;
int n,m,k;
int a,b,e;
char s[N];
int str[N];
int sa[N],rk[N],h[N],c[N],x[N],y[N];
void get_sa(){
for(int i = 1 ; i <= m ; ++i ) c[i] = 0;
for(int i = 1 ; i <= n ; ++i ) c[x[i] = str[i]]++;
for(int i = 2 ; i <= m ; ++i ) c[i] += c[i - 1];
for(int i = n ; i ; i--) sa[c[x[i]]--] = i;
for(int k = 1 ; k <= n ; k <<= 1){
int num = 0;
for(int i = n - k + 1 ; i <= n ; ++i ) y[++num] = i;
for(int i = 1 ; i <= n ; ++i ){
if(sa[i] > k){
y[++num] = sa[i] - k;
}
}
for(int i = 1 ; i <= m ; ++i ) c[i] = 0;
for(int i = 1 ; i <= n ; ++i ) c[x[i]]++;
for(int i = 2 ; i <= m ; ++i ) c[i] += c[i - 1];
for(int i = n ; i ; i--) sa[c[x[y[i]]]--] = y[i],y[i] = 0;
swap(x,y);
x[sa[1]] = 1,num = 1;
for(int i = 2 ; i <= n ; ++i ){
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
}
if(num == n) break;
m = num;
}
}
void get_h(){
for(int i = 1 ; i <= n ; ++i ) rk[sa[i]] = i;
for(int i = 1,k = 0; i <= n; ++i ){
if(rk[i] == 1) continue;
if(k) k--;
int j = sa[rk[i] - 1];
while(j + k <= n && i + k <= n && str[i + k] == str[j + k]) k++;
h[rk[i]] = k;
}
}
int root[N];
struct node{
int l,r,cnt;
}tr[N * 22];
int f[N][22];
void init(){
for(int i = 1 ; i <= n ; ++i ) f[i][0] = h[i];
for(int i = 1 ; i < 22 ; ++i ){
for(int j = 1 ; j + (1 << i) - 1 <= n ; ++j ){
f[j][i] = min(f[j][i - 1],f[j + (1 << i - 1)][i - 1]);
}
}
}
int get(int l,int r){
int t = log2(r - l + 1.0);
return min(f[l][t], f[r - (1 << t) + 1][t]);
}
bool check1(int mid,int d){
return get(mid + 1,a) >= d;
}
bool check2(int mid,int d){
return get(a + 1,mid) >= d;
}
int idx;
int build(int l,int r){
int u = ++idx;
tr[u].cnt = 0;
if(l == r) return u;
int mid = l + r >> 1;
tr[u].l = build(l,mid);
tr[u].r = build(mid + 1,r);
return u;
}
void pushup(int u){
tr[u].cnt = tr[tr[u].l].cnt + tr[tr[u].r].cnt;
}
int insert(int p,int l,int r,int k){
int u = ++idx;
tr[u] = tr[p];
if(l == r){
tr[u].cnt++;
return u;
}
int mid = l + r >> 1;
if(k <= mid) tr[u].l = insert(tr[p].l,l,mid,k);
else tr[u].r = insert(tr[p].r,mid + 1,r,k);
pushup(u);
return u;
}
int query(int p,int q,int l,int r,int k){
if(!q) return -1;
if(l == r) return l;
int mid = l + r >> 1;
int t = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
if(t >= k) return query(tr[p].l,tr[q].l,l,mid,k);
return query(tr[p].r,tr[q].r,mid + 1,r,k - t);
}
void solve(){
idx = 0;
scanf("%d%d%s",&n,&k,s + 1);
m = 30;
for(int i = 1 ; i <= n ; ++i ) str[i] = s[i] - 'a' + 1;
get_sa();
get_h();
init();
root[0] = build(1,n);
for(int i = 1 ; i <= n ; ++i ){
root[i] = insert(root[i - 1],1,n,sa[i]);
}
while(k--){
scanf("%d%d%d",&a,&b,&e);
int d = b - a + 1;
a = rk[a];
int l = 1,r = a;
while(l < r){
int mid = l + r >> 1;
if(check1(mid,d)) r = mid;
else l = mid + 1;
}
int nl = l;
if(get(a,a) < d) nl = a;
l = a + 1,r = n;
while(l < r){
int mid = l + r + 1 >> 1;
if(check2(mid,d)) l = mid;
else r = mid - 1;
}
int nr = l;
if(get(a + 1,a + 1) < d) nr = a;
if(nr - nl + 1 < e) puts("-1");
else printf("%d\n",query(root[nl - 1],root[nr],1,n,e));
}
for(int i = 1 ; i <= idx ; ++i ) tr[i].cnt = tr[i].l = tr[i].r = 0;
}
signed main(){
int tt;
scanf("%d",&tt);
while(tt--)
solve();
return 0;
}
/*
*
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/