Jzoj3351 神牛养成计划2
前文再续,书接上回,话说神牛yxr成功培育出神牛细胞,可最终培育出来的生物体却让他大失所望……
后来,他从某GD女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛yxr很生气,但他知道基因突变有低频性,说不定还有一些优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面的你懂的。
神牛yxr现在知道了N个细胞的DNA序列,它们是若干个由小写字母组成的字符串(为什么不是ATCG,因为突变得太厉害)。一个优秀基因是两个字符串s1和s2,当且仅当s1是某序列的前缀同时s2是这个序列的后缀时,神牛yxr认为这个序列拥有这个优秀基因。现在神牛yxr知道了M个优秀基因的s1和s2,他想知道对于给定的优秀基因,有多少个细胞的DNA序列拥有它。
题意就是求有多少个串前缀是s1后缀是s2
用SAM不太方便,hash也不太好搞
那么我们考虑一下用Trie
我们先将所有的DNA序列插入到Trie中
那么显然,一次查询我们可以视为查Trie上一个子树有多少串满足后缀是s2
考虑对每个串按照在Trie中的顺序标号,再将每个串反过来插到另一个trie上面
显然拥有同一个前缀的串,编号是连续的,拥有同一个后缀的串在一个子树中
那么问题就变成了,在第二个Trie的一个子树中查找编号在[l,r]的方案个数
可以用一个dfs序加上主席树完成
(p.s这种数据结构题还是比较好打的毕竟思路清晰不易错)
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<bitset>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 2010
#define M 2000010
#define mid (l+r>>1)
using namespace std;
struct tree{ int l,r,s; } s[N<<4];
int n,m,cnt=0,tot=0,l[M<<1],r[M<<1],son[M<<1][26],c[M<<1];
int sa[N],rk[N],clk=0,r1,r2,wl[M<<1],wr[M<<1],d[M],rt[M],L[N]; char str[M+N],q[M];
inline char* insert(char* s,int x,int p){
for(;*s;++s)
x=son[x][*s-'a']?son[x][*s-'a']:son[x][*s-'a']=++cnt;
c[x]=p; return --s;
}
inline void dfs(int x){
if(c[x]){
sa[++clk]=c[x]; rk[c[x]]=clk; l[x]=r[x]=clk;
} else l[x]=n;
for(int j=0;j<26;++j)
if(son[x][j]){
dfs(son[x][j]);
l[x]=min(l[x],l[son[x][j]]);
r[x]=max(r[x],r[son[x][j]]);
}
}
inline void rinsert(char* s,int x,int p){
for(;*s;--s)
x=son[x][*s-'a']?son[x][*s-'a']:son[x][*s-'a']=++cnt;
c[x]=p;
}
inline void dfs2(int x){
wl[x]=++clk; d[clk]=c[x];
for(int j=0;j<26;++j)
if(son[x][j]) dfs2(son[x][j]);
wr[x]=clk;
}
inline void ins(int l,int r,int r1,int& r2,int k){
r2=++tot; s[r2].s=s[r1].s+1;
if(l==r) return;
if(k<=mid){ s[r2].r=s[r1].r; ins(l,mid,s[r1].l,s[r2].l,k); }
else{ s[r2].l=s[r1].l; ins(mid+1,r,s[r1].r,s[r2].r,k); }
}
inline int g(int x,char* s,int lst){
for(;*s;++s)
x=son[x][(*s-'a'+lst)%26];
return x;
}
inline int query(int l,int r,int r1,int r2,int k){
if(l==r) return 0;
if(k<=mid) return query(l,mid,s[r1].l,s[r2].l,k);
else return s[s[r2].l].s-s[s[r1].l].s+query(mid+1,r,s[r1].r,s[r2].r,k);
}
int main(){
scanf("%d",&n); r1=++cnt; r2=++cnt;
for(int i=1,x;i<=n;++i){
scanf("%s",str+L[i]);
x=strlen(str+L[i])+1; L[i+1]=L[i]+x;
insert(str+L[i],r1,i);
}
dfs(r1); clk=0;
for(int i=1;i<=n;++i)
rinsert(str+L[i+1]-2,r2,rk[i]);
dfs2(r2); ++n;
for(int i=1;i<=clk;++i)
if(!d[i]) rt[i]=rt[i-1];
else ins(1,n,rt[i-1],rt[i],d[i]);
scanf("%d",&m);
for(int x,y,lst=0;m--;){
scanf("%s",q);
x=g(r1,q,lst);
scanf("%s",q); y=strlen(q); reverse(q,q+y);
y=g(r2,q,lst);
lst=query(1,n,rt[wl[y]-1],rt[wr[y]],r[x]+1)-query(1,n,rt[wl[y]-1],rt[wr[y]],l[x]);
printf("%d\n",lst);
}
}