题意:查询子串在原串中第k次出现的位置
思路: ST表 + 主席树 + 后缀数组
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
const lint maxn = 100000 + 10;
const lint log_maxn = 20;
typedef int lint;
struct PST_BASE {
//0 is invalid
const static int MAX_NODE = maxn * log_maxn, MAXN = maxn;
int n, tot, roots[MAXN], lson[MAX_NODE], rson[MAX_NODE], data[MAX_NODE];
//Assume that maxv and n are given
void Init(int _n) {
//The content at the index 0 is never modified. So they are always 0
n = _n;
tot = 0;
memset(roots, 0, (n + 1) * sizeof(roots[0]));
}
void Init(int a[], int _n, int maxv) {
Init(_n);
for (int i = 1; i <= n; ++i)
Insert(roots[i-1], roots[i], 1, maxv, a[i], 1);
}
void Insert(int from, int &rt, int l, int r, int x, int num) {
if (!rt) {
rt = ++tot;
lson[rt] = rson[rt] = data[rt] = 0;
}
data[rt] = data[from] + num;
if (l < r) {
int mid = (l + r) >> 1;
if (x <= mid) {
Insert(lson[from], lson[rt], l, mid, x, num);
rson[rt] = rson[from];
} else {
lson[rt] = lson[from];
Insert(rson[from], rson[rt], mid+1, r, x, num);
}
}
}
int Query(int L_rt, int R_rt, int l, int r, int k) {
if (l == r)
return l;
int mid = (l+r) >> 1;
int data_lc = data[lson[R_rt]] - data[lson[L_rt]];
if (data_lc >= k)
return Query(lson[L_rt], lson[R_rt], l, mid, k);
else
return Query(rson[L_rt], rson[R_rt], mid+1, r, k-data_lc);
}
}tree;
struct suffix{
int c[maxn],sa[maxn],t1[maxn],t2[maxn],m,n,h[maxn],height[maxn],rk[maxn],s[maxn];
void Build_SA(int len){
m = 0;
int* x = t1,*y = t2;
n = len;
for( int i = 0;i < n;i++ ) m = max( m,s[i] );
for( int i = 0;i <= m;i++ ) c[i] = 0;
for( int i = 0;i < n;i++ ) c[ x[i] = s[i] ]++;
for( int i = 1;i <= m;i++ ) c[i] += c[i-1];
for( int i = n-1;i >= 0;i-- ) {
sa[ --c[ x[i] ] ] = i;
}
for( int k = 1;k < n;k <<= 1 ){
int cnt = 0;
for( int i = n - 1;i >= n-k;i-- ) y[cnt++] = i;
for( int i = 0;i < n;i++ ) if( sa[i] >= k ) y[cnt++] = sa[i]-k;
for( int i = 0;i <= m;i++ ) c[i] = 0;
for( int i = 0;i < n;i++ ) c[ x[i] ]++;
for( int i = 1;i <= m;i++ ) c[i] += c[i-1];
for( int i = cnt-1;i >= 0;i-- ) sa[ --c[ x[ y[i] ] ] ] = y[i];
swap( x,y );
int num = 0;
x[ sa[0] ] = 0;
for( int i = 1;i < n;i++ ){
if( y[ sa[i-1] ] != y[ sa[i] ] || y[ sa[i-1]+k ] != y[ sa[i]+k ] ){
x[ sa[i] ] = ++num;
}else{
x[ sa[i] ] = num;
}
}
if( num == n-1 ) return;
m = num;
}
}
void getheight(){
for( int i = 0;i < n;i++ ){
rk[ sa[i] ] = i;
}
int cnt = 1;
h[ sa[0] ] = 0;
height[ 0 ] = 0;
for( int i = 0;i < n;i++ ){
if(cnt)cnt--;
while( rk[i] >= 1 && i + cnt < n &&sa[rk[i]-1]+cnt < n && s[ sa[rk[i]-1]+cnt ] == s[ i+cnt ] ) cnt++;
h[ i ] = cnt;
height[ rk[i] ] = cnt;
}
//cout << "debug" << endl;
}
}g;
int rmq[maxn][20],lg[maxn];
void init( int s,int t ){
lint dt = t-s+1;
lg[1] = 0;
for( lint i = 2;i <= dt;i++ ) lg[i] = i&(i-1) ? lg[i-1] : lg[i-1] + 1;
}
void build2( int s,int t,int rmq[][20] ){
int dt = t-s;
for( int i = s;i < t;i++ ){
rmq[i][0] = g.height[i];
}
for( int i = 1;i <= lg[dt];i++ ){
for( int j = s;j <= t;j++ ){
if( j+(1<<i)-1 > t ) continue;
rmq[j][i] = min( rmq[j][ i-1 ],rmq[ j + (1 << i-1 ) ][ i-1 ] );
}
}
}
lint len;
int lcp( int x,int y,int rmq[][20] ){ // x和y为排名,输出 x和y 的lcp
x++; y++;
if( x > y ) swap( x,y );
if( x >= len || y > len ) return 0;
int k = lg[y-x];
return min( rmq[x][k],rmq[ y - ( 1 << k ) ][k] );
}
int n;
vector<int> ve;
int solve( int l,int r,int k ){
int pos = g.rk[l-1];
int len = r-l+1;
int fi,en;
int L = -1,R = pos;
while(L!=R-1){
int mid =L+R>>1;
if( lcp( mid,pos,rmq ) < len ){
L = mid;
}else R = mid;
}
fi = R;
L = pos,R = n;
while(L!=R-1){
int mid = L+R>>1;
if(lcp( pos,mid,rmq ) < len ){
R = mid;
}else L = mid;
}
en = R;
if( en-fi < k ) return -1;
int res = tree.Query(tree.roots[fi+1-1], tree.roots[en+1-1], 1, n, k);
return res;
}
char s[maxn];
int a[maxn];
int main()
{
int T;
scanf("%d",&T);
init( 0,100004 );
while(T--){
int q;
scanf("%d%d",&n,&q);len = n;
scanf("%s",s);
for( int i= 0;i < n;i++ ){
g.s[i] = s[i];
}
g.Build_SA(n);g.getheight();
for( int i = 1;i <= n;i++ ){
a[i] = g.sa[i-1]+1;
}
//from 1
tree.Init(a, n, n);
build2( 0,n,rmq );
int l,r,k;
for( int i = 1;i <= q;i++ ){
scanf("%d%d%d",&l,&r,&k);
int pos = solve( l,r,k );
printf("%d\n",pos);
}
}
return 0;
}