【BZOJ-4212】神牛的养成计划 Trie树 + 可持久化Trie树
4212: 神牛的养成计划
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 136 Solved: 27
[Submit][Status][Discuss]
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
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
7
3
5
5
1
3
5
10
4
HINT
N<=2000
L1<=2000000
M<=100000
L2<=2000000
Source
Solution
首先对所有串按字典序排序,按字典序正序建Trie树,并在Trie树上记录节点区间。
然后查询一个前缀,在Trie树上跑到的节点所包含的区间即是可能成为答案的串区间,由于之前的排序,所以区间一定连续。
然后逆序建可持久化Trie树,对于前缀得到的区间LR,再利用可持久化Trie树跑后缀得到满足的子串树。
复杂度O(LenlogLen)排序暴力比较貌似有点智障,把垃圾排序去掉能做到O(Len)。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #include<map> #include<cstdio> using namespace std; #define MAXN 2000010 int N,M,id[MAXN],last,st[2010],ed[2010]; char S[MAXN],s1[MAXN],s2[MAXN]; inline bool cmp( int x, int y) { int st1=st[x],st2=st[y],ed1=ed[x],ed2=ed[y],l=min(ed1-st1,ed2-st2)+1; for ( int i=1; i<=l; i++) { if (S[st1]==S[st2]) st1++,st2++; else return S[st1]<S[st2]; } return ed1-st1<ed2-st2; } namespace Trie{ int ls[MAXN],rs[MAXN],sz=1,son[MAXN][26]; inline void Insert( int x, int y) { int now=1; for ( int i=st[x]; i<=ed[x]; i++) { int c=S[i]- 'a' ; if (son[now][c]) now=son[now][c]; else son[now][c]=++sz,now=son[now][c]; ls[now]=min(ls[now],y); rs[now]=max(rs[now],y); } } inline int Query() { int len= strlen (s1),now=1; for ( int i=0; i<len; i++) { int c=s1[i]- 'a' ; if (!son[now][c]) return -1; now=son[now][c]; } return now; } inline void Clear() { memset (ls,63, sizeof (ls)); memset (rs,0, sizeof (rs));} } namespace PrTrie{ int root[MAXN+20010],sz,sum[MAXN+20010],son[MAXN+20010][26]; inline void Insert( int &x, int y, int k) { int now=x=++sz; for ( int i=st[k]; i<=ed[k]; i++) { for ( int j=0; j<26; j++) son[now][j]=son[y][j]; sum[now]=sum[y]+1; int c=S[i]- 'a' ; y=son[y][c],son[now][c]=++sz,now=son[now][c]; } sum[now]=sum[y]+1; } inline int Query( int L, int R) { int len= strlen (s2),re=0;; for ( int i=0; i<len; i++) { int c=s2[i]- 'a' ; if (sum[son[R][c]]-sum[son[L][c]]) L=son[L][c],R=son[R][c]; else return 0; } return sum[R]-sum[L]; } } int main() { // freopen("godcow.in","r",stdin); // freopen("godcow.out","w",stdout); scanf ( "%d" ,&N); for ( int i=1; i<=N; i++) { scanf ( "%s" ,S+ed[i-1]+1); id[i]=i; st[i]=ed[i-1]+1; ed[i]=st[i]+ strlen (S+ed[i-1]+1)-1; } stable_sort(id+1,id+N+1,cmp); // for (int i=1; i<=N; i++) cout<<id[i]<<" "; cout<<endl; Trie::Clear(); for ( int i=1; i<=N; i++) Trie::Insert(id[i],i); for ( int i=1; i<=N; i++) reverse(S+st[i],S+ed[i]+1); for ( int i=1; i<=N; i++) { using namespace PrTrie; Insert(root[i],root[i-1],id[i]); } scanf ( "%d" ,&M); while (M--) { scanf ( "%s%s" ,s1,s2); int l1= strlen (s1),l2= strlen (s2); for ( int i=0; i<l1; i++) { int tmp=s1[i]- 'a' ; tmp+=last; tmp%=26; tmp+= 'a' ; s1[i]=tmp; } for ( int i=0; i<l2; i++) { int tmp=s2[i]- 'a' ; tmp+=last; tmp%=26; tmp+= 'a' ; s2[i]=tmp; } reverse(s2,s2+l2); int pos=Trie::Query(),L,R; if (pos==-1) printf ( "%d\n" ,last=0); else { L=Trie::ls[pos],R=Trie::rs[pos]; // printf("%d %d\n",L,R); using namespace PrTrie; printf ( "%d\n" ,last=Query(root[L-1],root[R])); } } return 0; } |
用cout输出一直无故RE...黑人问号...
——It's a lonely path. Don't make it any lonelier than it has to be.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥