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);
	}
}

posted @ 2018-04-20 20:40  扩展的灰(Extended_Ash)  阅读(157)  评论(0编辑  收藏  举报