裸题,倒着建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; }