裸题,倒着建trie树,所有符合要求的串都在它的子树里,然后就是查询子树第k小了,用dfs序+主席树就可以了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 300010
using namespace std;
int lch[maxn*20],rch[maxn*20],root[maxn],cnt[maxn*20];
int ch[maxn][26];
char s[maxn];
int in[maxn],out[maxn],id[maxn],a[maxn];
int head[maxn],next[maxn],to[maxn];
int tot,num,n,m;
void add(int x,int y)
{
tot++;to[tot]=y;next[tot]=head[x];head[x]=tot;
}
void insert(int p)
{
int len=strlen(s),x=0;
for (int i=len-1;i>=0;i--)
if (ch[x][s[i]-'a']) x=ch[x][s[i]-'a'];
else ch[x][s[i]-'a']=++num,x=num;
add(x,p);
}
void dfs(int x)
{
int num=tot;
for (int p=head[x];p;p=next[p]) a[++tot]=to[p];
for (int i=0;i<26;i++)
if (ch[x][i]) dfs(ch[x][i]);
for (int p=head[x];p;p=next[p]) in[to[p]]=num,out[to[p]]=tot;
}
int modify(int pre,int l,int r,int x)
{
int now=++tot;
if (l==r)
{
cnt[now]=cnt[pre]+1;lch[now]=rch[now]=0;
}
else
{
int mid=(l+r)/2;
if (x<=mid)
{
rch[now]=rch[pre];lch[now]=modify(lch[pre],l,mid,x);
}
else
{
lch[now]=lch[pre];rch[now]=modify(rch[pre],mid+1,r,x);
}
cnt[now]=cnt[lch[now]]+cnt[rch[now]];
}
return now;
}
int query(int root1,int root2,int l,int r,int k)
{
int mid=(l+r)/2;
if (l==r) return l;
if (cnt[root2]-cnt[root1]<k) return -1;
if (cnt[lch[root2]]-cnt[lch[root1]]>=k) return query(lch[root1],lch[root2],l,mid,k);
else return query(rch[root1],rch[root2],mid+1,r,k-(cnt[lch[root2]]-cnt[lch[root1]]));
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
insert(i);
}
tot=0;
dfs(0);
tot=0;
root[0]=lch[0]=rch[0]=cnt[0]=0;
for (int i=1;i<=n;i++) root[i]=modify(root[i-1],1,n,a[i]);
for (int i=1;i<=n;i++)
{
int k;
scanf("%d",&k);
printf("%d\n",query(root[in[i]],root[out[i]],1,n,k));
}
return 0;
}