开始本来以为是AC自动机,后来发现不行,跳fail的时候没用的状态太多了。
正解倒着建Trie
然后答案就在子树里
dfs序+主席树求子树中第k大
注意有重串,用链表搞一下
1A,表扬自己~
trie和主席树的变量名重了改的好丑。。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; struct Trie { int w[30],last,fail; void clean(){memset(w,0,sizeof(w));last=0;} }tr[310000];int trlen,next[110000]; char ss[110000]; void insert(int id) { int now=0,len=strlen(ss+1); for(int i=len;i>=1;i--) { int x=ss[i]-'a'+1; if(tr[now].w[x]==0) tr[now].w[x]=++trlen, tr[trlen].clean(); now=tr[now].w[x]; } next[id]=tr[now].last; tr[now].last=id; } //-------------Trie-------------------- struct chairman_tree { int lc,rc,c; }ch[6100000];int chlen,rt[310000]; int maketree(int now,int l,int r,int p) { if(now==0) { now=++chlen; ch[now].lc=ch[now].rc=0; ch[now].c=0; } ch[now].c++; if(l==r)return now; else { int mid=(l+r)/2; if(p<=mid)ch[now].lc=maketree(ch[now].lc,l,mid,p); else ch[now].rc=maketree(ch[now].rc,mid+1,r,p); return now; } } int merge(int x,int y) { if(x==0||y==0)return x+y; ch[x].c+=ch[y].c; ch[x].lc=merge(ch[x].lc,ch[y].lc); ch[x].rc=merge(ch[x].rc,ch[y].rc); return x; } //init~~~~~~~ int getk(int x,int y,int l,int r,int k) { if(k>ch[y].c-ch[x].c)return -1; if(l==r)return l; int lsum=ch[ch[y].lc].c-ch[ch[x].lc].c; int mid=(l+r)/2; if(lsum>=k)return getk(ch[x].lc,ch[y].lc,l,mid,k); else return getk(ch[x].rc,ch[y].rc,mid+1,r,k-lsum); } //--------------chairman tree----------------- const int m=1001000; int z,l[310000],r[310000]; int hh[110000]; void dfs(int now) { l[now]=++z; for(int k=tr[now].last;k;k=next[k]) { rt[z]=maketree(rt[z],1,m,k); hh[k]=now; } rt[z]=merge(rt[z],rt[z-1]); for(int x=1;x<=26;x++) { int son=tr[now].w[x]; if(son!=0)dfs(son); } r[now]=z; } int main() { int n; scanf("%d",&n); trlen=0;tr[trlen].clean(); for(int i=1;i<=n;i++) { scanf("%s",ss+1); insert(i); } memset(rt,0,sizeof(rt)); z=0;dfs(0); int k; for(int i=1;i<=n;i++) { scanf("%d",&k); printf("%d\n",getk(rt[l[hh[i]]-1],rt[r[hh[i]]],1,m,k)); } return 0; }