链接
题解
后缀数组上二分确定区间,然后查询主席树区间第 k k k大
代码
#include <bits/stdc++.h>
#define linf (1ll<<60)
#define iinf 0x3f3f3f3f
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
using namespace std;
#define maxn 100010
#define maxk 17
typedef long long ll;
typedef pair<ll,ll> pll;
struct SuffixArray
{
int sa[maxn], rank[maxn], ws[maxn], wv[maxn], wa[maxn], wb[maxn], height[maxn], st[maxk+2][maxn], N;
bool cmp(int *r, int a, int b, int l){return r[a]==r[b] and r[a+l]==r[b+l];}
void clear()
{
cl(sa), cl(rank), cl(ws), cl(wv), cl(wa), cl(wb), cl(height);
}
void build(int *r, int n, int m)
{
N=n;
n++;
int i, j, k=0, p, *x=wa, *y=wb, *t;
for(i=0;i<m;i++)ws[i]=0;
for(i=0;i<n;i++)ws[x[i]=r[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i;
for(p=j=1;p<n;j<<=1,m=p)
{
for(p=0,i=n-j;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=0;i<n;i++)wv[i]=x[y[i]];
for(i=0;i<m;i++)ws[i]=0;
for(i=0;i<n;i++)ws[wv[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,i=1,x[sa[0]]=0;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
for(i=0;i<n;i++)rank[sa[i]]=i;
for(i=0;i<n-1;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}
void build_st() //st表
{
int i, k;
for(i=1;i<=N;i++)st[0][i]=height[i];
for(k=1;k<=maxk;k++)
for(i=1;i+(1<<k)-1<=N;i++)
st[k][i]=min(st[k-1][i],st[k-1][i+(1<<k-1)]);
}
int lcp(int x, int y) //最长公共前缀
{
int l=rank[x], r=rank[y];
if(l>r)swap(l,r);
if(l==r)return N-sa[l];
int t=log2(r-l);
return min(st[t][l+1],st[t][r-(1<<t)+1]);
}
}SA;
int ndtot, N;
struct segtree{int l, r, size;segtree *ch[2];}pool[maxn*30], *root[maxn];
void ins(segtree *pre, segtree *now, int pos)
{
int mid=(pre->l+pre->r)>>1;
*now=*pre;now->size++;
if(pre->l==pre->r)return;
if(pos<=mid)ins(pre->ch[0],now->ch[0]=pool+ ++ndtot,pos);
if(pos>mid)ins(pre->ch[1],now->ch[1]=pool+ ++ndtot,pos);
}
int find(segtree *pre, segtree *now, int k)
{
int sz;
if(pre->l==pre->r)return pre->l;
sz=now->ch[0]->size-pre->ch[0]->size;
if(k<=sz)return find(pre->ch[0],now->ch[0],k);
return find(pre->ch[1],now->ch[1],k-sz);
}
void build(segtree *p, int l, int r)
{
int mid=(l+r)>>1;
p->l=l, p->r=r, p->size=0;
if(l==r)return;
build(p->ch[0]=pool+ ++ndtot,l,mid);
build(p->ch[1]=pool+ ++ndtot,mid+1,r);
}
int r[maxn];
char s[maxn];
pair<int,int> get_interval(int p, int len)
{
int l, r, mid;
pair<int,int> pr;
l=1, r=SA.rank[p];
while(l<r)
{
mid=l+r>>1;
if(SA.lcp(p,SA.sa[mid])>=len)r=mid;
else l=mid+1;
}
pr.first = l;
l=SA.rank[p], r=N;
while(l<r)
{
mid=l+r+1>>1;
if(SA.lcp(p,SA.sa[mid])>=len)l=mid;
else r=mid-1;
}
pr.second=l;
return pr;
}
int main()
{
int T, a, b, i, Q, L, k;
cin>>T;
while(T--)
{
scanf("%d%d",&N,&Q);
scanf("%s",s);
for(i=0;i<N;i++)r[i]=s[i];
r[N]=0;
SA.build(r,N,300);
SA.build_st();
ndtot=0;
build(root[0]=pool+ ++ndtot,1,N);
for(i=1;i<=N;i++)ins(root[i-1],root[i]=pool+ ++ndtot,SA.sa[i]+1);
while(Q--)
{
scanf("%d%d%d",&a,&b,&k);
auto I = get_interval(a-1,b-a+1);
if(I.second-I.first+1 < k)
{
printf("-1\n");
}
else printf("%d\n",find(root[I.first-1],root[I.second],k));
}
}
return 0;
}