本题被描述者现在才来做这道题。。。对我就是KPM。。。先Orz云神吧~
把所有字符串反向建立一棵Trie,然后建立DFS序,那么Trie上的每个点的子树就对应着DFS序上的一段数。
然后将每个字符串的标号插入,无修改的话只需要主席树。
#include <cstdlib> #include <cstdio> #include <cctype> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #include <queue> #define rep(i, l, r) for (int i=l; i<=r; i++) #define down(i, l, r) for (int i=l; i>=r; i--) #define clr(x, c) memset(x, c, sizeof(x)) #define t(x) Tree[x] #define maxn 100009 #define maxl 200009 using namespace std; inline int read() { int x=0; char ch=getchar(); while (!isdigit(ch)) ch=getchar(); while (isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x; } struct node{int s; node *l, *r;} *blank=new(node), *Tree[maxl]; struct sr{int a, b;} q[maxn]; int n, z, now, t[maxl][26], l[maxl], r[maxl], w[maxn]; char s[maxl]; inline bool cmp(sr a, sr b){return l[a.a]<l[b.a];} void Add(int k, int l, int r, node *u, node*&t) { if (t==blank) t=new(node), t->l=t->r=blank, t->s=0; t->s=u->s+1; if (l==r) return; int mid=(l+r)>>1; if (k<=mid) t->r=u->r, Add(k, l, mid, u->l, t->l); else t->l=u->l, Add(k, mid+1, r, u->r, t->r); } inline int Query(int l, int r, int k) { if (t(r)->s-t(l)->s<k) return -1; k--; int L=1, R=n; node *u=t(l), *v=t(r); while (L<R) { int mid=(L+R)>>1, sum=v->l->s-u->l->s; if (sum<=k) L=mid+1, v=v->r, u=u->r, k-=sum; else R=mid, v=v->l, u=u->l; } return L; } void dfs(int x){l[x]=++now; rep(i, 0, 25) if (t[x][i]) dfs(t[x][i]); r[x]=now;} inline void Init() { blank->l=blank->r=blank, blank->s=0; t(0)=new(node), t(0)->l=t(0)->r=blank, t(0)->s=0; } int main() { n=read(); Init(); rep(i, 1, n) { scanf("%s", s); int len=strlen(s), now=0; down(j, len-1, 0) t[now][s[j]-'a']==0 ? now=t[now][s[j]-'a']=++z : now=t[now][s[j]-'a']; q[i].a=now, q[i].b=i, w[i]=now; } now=0; dfs(0); sort(q+1, q+1+n, cmp); for(int i=1, k=1; k<=z+1; k++) { node *p=t(k-1); while (l[q[i].a]==k) Add(q[i++].b, 1, n, p, t(k)=blank), p=t(k); t(k)=p; } rep(i, 1, n) printf("%d ", Query(l[w[i]]-1, r[w[i]], read())); }