这题乍一看后缀相等很烦的样子……
其实如果把字符串倒过来,那么相等的后缀就可以转化成前缀,前缀相等扔进trie就可以了。
剩下无非是Trie的树链kth,主席树随便维护就好。
注意一个串彻底结束才能打val++。而且因为主席树维护的权值是出现次数,连离散化都不用的。
#include<bits/stdc++.h> #define N 500010 using namespace std; int cnt,ch[N][26],val[N],in[N],out[N],tpos[N],n; int sumv[N<<2],ls[N<<2],rs[N<<2];char s[N]; vector<int> q[N]; void ins(int x,char *s){ int len=strlen(s);int now=0,u=0; for(int i=len-1;i>=0;i--,now=ch[now][u]){ u=s[i]-'a'; if(!ch[now][u])ch[now][u]=++cnt; } val[now]++;q[now].push_back(x); } void dfs(int x){ for(int i=0;i<val[x];i++)in[q[x][i]]=cnt+1; for(int i=0;i<val[x];i++)tpos[++cnt]=q[x][i]; for(int i=0;i<26;i++)if(ch[x][i])dfs(ch[x][i]); for(int i=0;i<val[x];i++)out[q[x][i]]=cnt; } void build(int x,int y,int l,int r,int q){ sumv[x]=sumv[y]+1; if(l==r)return;int mid=(l+r)>>1; if(q<=mid){ls[x]=++cnt;rs[x]=rs[y];build(ls[x],ls[y],l,mid,q);} else{ls[x]=ls[y];rs[x]=++cnt;build(rs[x],rs[y],mid+1,r,q);} } int query(int l,int r,int x,int y,int v){ if(l==r)return l; int mid=(l+r)>>1;int t=sumv[ls[y]]-sumv[ls[x]]; if(t>=v)return query(l,mid,ls[x],ls[y],v); else return query(mid+1,r,rs[x],rs[y],v-t); } inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9'); return f*x; } int main(){ n=read(); for(int i=1;i<=n;i++)scanf("%s",s),ins(i,s); cnt=0;dfs(0);cnt=n+1; for(int i=1;i<=n;i++)build(i+1,i,1,n,tpos[i]); for(int i=1;i<=n;i++){ int x=read(); if(sumv[out[i]+1]-sumv[in[i]]<x)puts("-1"); else printf("%d ",query(1,n,in[i],out[i]+1,x)); } return 0; }