给一个字符串S,若干个查询,每个查询k输出字典序第k小的S的子串。把字符串一次插入到自动机中,由于在不考虑父边的情况下,可以看做一个有向无环图,那么我们可在在这个图上进行dp,令dp[i]表示从节点i开始有多少个子串,转移dp[i]=dp[j]+1(存在一条边c使得i-->j),然后就是从根节点贪心走一遍就可以得到要求的串了。
另外吐槽一句SPOJ上的题卡时间卡的太凶残了....
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <string>
#include <cstring>
#include <stack>
using namespace std;
const int maxn=180010;
const int S=26;
int next[maxn][26];
char ch[maxn][26];
char str[maxn>>1];
int wtop[maxn];
int cnt[maxn];
int n,m,q;
int len,tot;
struct node
{
node *par,*go[S];
int val,cnt;
}*root,*tail,que[maxn],*top[maxn];
char ans[maxn];
int c[maxn];
inline int idx(char c)
{
return c-'a';
}
inline void add(int c,int l)
{
node *p=tail;
node *np=&que[tot++];
np->val=l;
while (p && p->go[c]==NULL) p->go[c]=np,p=p->par;
if (p==NULL) np->par=root;
else
{
node *q=p->go[c];
if (p->val+1==q->val) np->par=q;
else
{
node *nq=&que[tot++];
*nq=*q;
nq->val=p->val+1;
np->par=q->par=nq;
while (p&&p->go[c]==q) p->go[c]=nq,p=p->par;
}
}
tail=np;
}
inline void init()
{
//memset(que,0,sizeof que);
len=1;
tot=0;
root=tail=&que[tot++];
}
inline void slove(int k)
{
int now=0;
int l=0;
while (k)
{
for (int i=0; i<cnt[now]; i++)
{
if (k>que[next[now][i]].cnt)
k-=que[next[now][i]].cnt;
else
{
ans[l++]=ch[now][i];
k--;
now=next[now][i];
break;
}
}
}
ans[l]='\0';
puts(ans);
}
int main()
{
//freopen("a.txt","r",stdin);
//freopen("out.txt","w",stdout);
gets(str);
init();
int l=strlen(str);
for (int i=0; i<l; i++)
add(idx(str[i]),len++);
// memset(c,0,sizeof c);
// memset(wtop,0,sizeof wtop);
// memset(cnt,0,sizeof cnt);
for (int i=0; i<tot; i++)
c[que[i].val]++;
for (int i=1; i<len; i++)
c[i]+=c[i-1];
for (int i=0; i<tot; i++)
{
top[--c[que[i].val]]=&que[i];
wtop[c[que[i].val]]=i;
}
for (int i=0; i<tot; i++)
que[i].cnt=1;
for (int i=tot-1; i>=0; i--)
{
node *p=top[i];
for (int j=0; j<S; j++)
{
if (p->go[j])
{
int u=p-que,v=p->go[j]-que;
next[u][cnt[u]]=v;
ch[u][cnt[u]++]=j+'a';
p->cnt+=p->go[j]->cnt;
}
}
}
scanf("%d",&q);
while (q--)
{
scanf("%d",&m);
slove(m);
}
return 0;
}