bzoj4212(trie,可持久化字典树,dfs序)

Description
Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望……
后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛hzwer很生气,但他知道基因突变的低频性,说不定还有以下优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面你懂的……
黄学长现在知道了N个细胞的DNA序列,它们是若干个由小写字母组成的字符串。一个优秀的基因是两个字符串s1和s2,当且仅当s1是某序列的前缀的同时,s2是这个序列的后缀时,hzwer认为这个序列拥有这个优秀基因。
现在黄学长知道了M个优秀基因s1和s2,它们想知道对于给定的优秀基因,有多少个细胞的DNA序列拥有它。
Input
第一行:N,表示序列数
接下来N行,每行一个字符串,代表N个DNA序列,它们的总长为L1
接下来一个M,表示询问数
接下来M行,每行两个字符串s1和s2,由一个空格隔开,hzwer希望你能在线回答询问,所以s1等于“s1”的所有字符按字母表的顺序向后移动ans位(字母表是一个环),ans为上一个询问的答案,s2同理。例如ans=2 “s1”=qz
则s1=sb。对于第一个询问,ans=0
s1和s2的总长度为L2
Output
输出M行,每行一个数,第i行的数表示有多少个序列拥有第i个优秀基因。
Sample Input
10
emikuqihgokuhsywlmqemihhpgijkxdukjfmlqlwrpzgwrwozkmlixyxniutssasrriafu
emikuqihgokuookbqaaoyiorpfdetaeduogebnolonaoehthfaypbeiutssasrriafu
emikuqihgokuorocifwwymkcyqevdtglszfzgycbgnpomvlzppwrigowekufjwiiaxniutssasrriafu
emikuqihgokuorociysgfkzpgnotajcfjctjqgjeeiheqrepbpakmlixyxniutssasrriafu
emikuqihgokuorociysgfrhulymdxsqirjrfbngwszuyibuixyxniutssasrriafu
emikuqihgokuorguowwiozcgjetmyokqdrqxzigohiutssasrriafu
emikuqihgokuorociysgsczejjmlbwhandxqwknutzgdmxtiutssasrriafu
emikuqihgokuorociysgvzfcdxdiwdztolopdnboxfvqzfzxtpecxcbrklvtyxniutssasrriafu
emikuqihgokuorocsbtlyuosppxuzkjafbhsayenxsdmkmlixyxniutssasrriafu
emikuqihgokuorociysgfjvaikktsixmhaasbvnsvmkntgmoygfxypktjxjdkliixyxniutssasrriafu
10
emikuqihgokuorociysg yxniutssasrriafu
aiegqmedckgqknky eqpoowonnewbq
xfbdnjbazhdnhkhvb qrqgbnmlltlkkbtyn
bjfhrnfedlhrlolzfv qppxpoofxcr
zhdfpldcbjf stsidponnvnmmdvap
zhdfpldcbjfpjmjxdt gdstsidponnvnmmdvap
dlhjtphgfnjtnqnbhxr wxwmhtsrrzrqqhzet
bjfhrnfedlhrlolzfv frqppxpoofxcr
zhdfpldcbjf dponnvnmmdvap
ucyakgyxweakehes nondykjiiqihhyqvk
Sample Output
4
7
3
5
5
1
3
5
10
4
HINT
N<=2000
L1<=2000000
M<=100000
L2<=2000000
Source


先对所有母串建立 trie t r i e
考虑对前缀匹配的时候,匹配到的串的终止点肯定是在对应匹配点的位置的子树内,且这个子树内不可能有非匹配串的终止点
那我们结合 dfs d f s 序的思想
如果我们按照 dfs d f s 序把出现的串排序,一个前缀匹配到的字符串肯定是一段连续的区间
那我们只要吧排好序的串的反串建一个可持久化字典树即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
int ch[2][2000010][26] , tot1 , tot2 , root;
int rt[2010] , cnt;
int n , m , sum[2][2000010];
int L[2000010] , R[2000010];
int flag[2][2000010];
char s[2000010];
void insert1()
{
    int len = strlen(s+1) , x = root;
    rep(i,1,len)
    {
        if(!ch[0][x][s[i]-'a']) ch[0][x][s[i]-'a'] = ++tot1;
        sum[0][x]++;
        x = ch[0][x][s[i]-'a'];
    }
    sum[0][x]++;
    flag[0][x]++;
}
int insert2(int root,int last,int len)
{
    int tmp = root = ++tot2;
    repp(i,len,1)
    {
        rep(j,0,25) ch[1][root][j] = ch[1][last][j];
        int k = s[i]-'a';
        ch[1][root][k] = ++tot2;
        sum[1][root] = sum[1][last] + 1;
        root = ch[1][root][k];
        last = ch[1][last][k];
    }
    sum[1][root] = sum[1][last] + 1;
    return tmp;
}
void dfs(int x,int st,int dep)
{
    if(flag[0][x] > 0) rep(i,1,flag[0][x]) cnt++,rt[cnt] = insert2(rt[cnt],rt[cnt-1],dep-1); 
    L[x] = st;R[x] = st+sum[0][x] - 1;
    rep(i,0,25)
        if(ch[0][x][i])
        {
            s[dep] = (char)i+'a';
            dfs(ch[0][x][i],st,dep+1);
            st += sum[0][ch[0][x][i]];
        }
}
P query1()
{
    int x = root , len = strlen(s+1);
    rep(i,1,len)
    {
        if(!ch[0][x][s[i]-'a']) return mp(0,0);
        x = ch[0][x][s[i]-'a'];
    }
    return mp(L[x],R[x]);
}
int query2(int l,int r)
{
    int x = l , y = r , len = strlen(s+1);
    repp(i,len,1)
    {
        if( sum[1][ch[1][y][s[i]-'a']] - sum[1][ch[1][x][s[i] - 'a']] )
            x = ch[1][x][s[i]-'a'] , y = ch[1][y][s[i]-'a'];
        else return 0;
    }
    return sum[1][y] - sum[1][x];
}
void init()
{
    scanf("%d",&n);root = tot1 = tot2 = 1;
    rep(i,1,n)
    {
        scanf("%s",s+1);
        insert1();
    }
}
int main()
{
    init();
    dfs(root,1,1);
    scanf("%d",&m);
    int last = 0;
    rep(x,1,m)
    {
        scanf("%s",s+1);
        int len = strlen(s+1);
        rep(i,1,len) s[i] = (char)((int)((s[i]-'a' + last) % 26)+'a');
        P now = query1();
        scanf("%s",s+1);
        len = strlen(s+1);
        rep(i,1,len) s[i] = (char)((int)((s[i]-'a' + last) % 26)+'a');
        if(now.first == 0 || now.second == 0) printf("0\n") , last = 0;
        else
        {
            int ans = query2(rt[now.first-1],rt[now.second]);
            last = ans;
            printf("%d\n",ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值