【题目地址】点击打开链接
【题目大意】
给定一个字符串s,每次提问它的第k小子串。
如果某个字符串在s中重复出现,将其看做一个子串。
【分析】
•我们引入另一个域x.size,表示从x点开始向后遍历得到的子串数,从原点开始沿正向转移边深搜可以得到。其作用与平衡树中的size域相同,在自动机中查找第K大子串的方式可以参照在平衡树中找第K大元素的方法。
【代码】
/****************************
ID:Ciocio
LANG:C++
DATE:2014-2-2
TASK:Music Compilation
****************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define MAXN 90010
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rrep(i,b,a) for(int i=b;i>=a;--i)
struct SAM{
int tot,last,m;
int pre[MAXN<<1],go[MAXN<<1][26],step[MAXN<<1];
int sz[MAXN<<1];
int head[MAXN<<1],next[MAXN*2*26],ch[MAXN*2*26];
void new_node(int s){
step[++tot]=s;
pre[tot]=0;
memset(go[tot],0,sizeof go[tot]);
}
void build(char* s){
tot=0;last=1;
new_node(0);
int n=strlen(s);
rep(i,0,n-1){
new_node(step[last]+1);
int c=s[i]-'a';
int p=last,np=tot,q,nq;
for(;p&&!go[p][c];p=pre[p]) go[p][c]=np;
if(!p)
pre[np]=1;
else{
q=go[p][c];
if(step[q]==step[p]+1) pre[np]=q;
else{
new_node(step[p]+1);
nq=tot;
pre[nq]=pre[q];
pre[np]=
pre[q]=nq;
memcpy(go[nq],go[q],sizeof go[q]);
for(;p&&go[p][c]==q;p=pre[p]) go[p][c]=nq;
}
}
last=np;
}
m=0;
rep(i,1,tot)
rrep(j,25,0){
if(go[i][j]){
ch[++m]=j;
next[m]=head[i];
head[i]=m;
}
}
}
void dfs(int x){
sz[x]=1;
for(int i=head[x];i;i=next[i]){
int y=go[x][ch[i]];
if(y&&!sz[y]) dfs(y);
sz[x]+=sz[y];
}
}
void findkth(int k){
int p=1;
while(k){
for(int j=head[p];j;j=next[j]){
int i=ch[j];
if(k<=sz[go[p][i]]){
k--;
putchar(i+'a');
p=go[p][i];
break;
}
else{
k-=sz[go[p][i]];
}
}
}
cout<<endl;
}
};
char S[MAXN+10];
int Q;
SAM run;
int main(){
scanf("%s%d",S,&Q);
run.build(S);
run.dfs(1);
while(Q--){
int k;
scanf("%d",&k);
run.findkth(k);
}
return 0;
}