题解 P3879 【[TJOI2010]阅读理解】

· · 题解

这道题看一眼就知道这是个STL库里的map

******* dalao 专用分割线******

可能有的小朋友们还不知道Trie树是什么(虽然我也是刚刚才知道),我还是先讲一下Trie树吧。。

那什么时候会用到$Trie$树呢? 举个例子吧: 1. 就像这道题目一样,查寻这个单词在一句话中出现还是没有出现,非常简单么,$map$啊,~~短小精干~~ 2. 但是,如果给出$n$个单词和$m$组询问,询问是多少个单词的前缀,那么$map$的话就完美的$TLE$了,这个时候就要使用久违的$Trie$树了!! $Second$,先模拟一下$Trie$树的各种操作吧。 如果要插入 $CAI,CHANG,CHAO,CHEN,LAN,LI,LIU,LONG, 所建出的$Trie$树就是这样的。 ## 呈上图来: ![](https://cdn.luogu.com.cn/upload/pic/15735.png) ### 注意:$Trie$树的根节点是空的,然后在单词的末尾有个标记,这点事必不可少的。 $Then$,介绍一下$Trie$树的基本操作吧。 $A.$ $Insert$插入: 1. 首先要给所有的字母一个编号,其实并不用从$a...z$全部都编号,你会发现其实有很多字母是用不到的,所以只需要判断树中有没有这个单词的前缀,然后进行编号。 2. 编号完成后更新当前位置,接着进入下一个层。 #### 代码统一在后边统一粘上 $B.$ $Check$查询: 从$Trie$树的根开始,看有没有当前的字符,如果没有,就直接$break$掉,否则就跟新当前位置,进入下一层。 其实$Trie$树的常用操作就这两个,其实$Trie$树涉及的题目也不算很多,其实学习$Trie$树还可以为以后的$AC$自动机(~~就是用了这个算法就可以自动AC了~~)做一下铺垫。 ---- ---- 好了,对于$Trie$树的介绍就到这里吧,下面就说这个题目了,其实这个题目就是一道裸裸的$Trie$树模板,写出上边介绍的两个操作,再加上点~~高深~~的东西就可以$AC$了。 下边直接粘代码吧: ```cpp #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <iostream> using namespace std; char s[10010]; int nex[500010][26],n,cnt=0; bool b[500010][1010]; inline int read() { int k=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { k=k*10+ch-'0'; ch=getchar(); } return k*f; } inline void insert(int x) { scanf("%s",s+1); int l=strlen(s+1); int now=0; for(int i=1;i<=l;i++) { int p=s[i]-'a'; if(!nex[now][p]) //如果$Trie$树中没有这个单词的前缀就进行编号 nex[now][p]=++cnt; //上文中说到的编号 now=nex[now][p]; //接着深入一层,更新现在的位置 } b[now][x]=1; //这个单词在第x行出现了 } inline void check() { scanf("%s",s+1); int l=strlen(s+1); int now=0,flag=1; for(int i=1;i<=l;i++) { int p=s[i]-'a'; if(!nex[now][p]) //如果在Trie树中没有当前的字符,就可以直接break掉了 { flag=0; break; } now=nex[now][p]; //否则就更新位置 } if(flag) for(int i=1;i<=n;i++) //题面上说按字典序输出 if(b[now][i]) printf("%d ",i); //输出在哪些句子中出现过 puts(""); //相当于printf("\n");其实这个条件很容易看不到,一定要注意啊!! } int main() { n=read(); for(int i=1;i<=n;i++) { int x=read(); for(int j=1;j<=x;j++) //一个单词一个单词的插入Trie树里 insert(i); } int m=read(); for(int i=1;i<=m;i++) check(); return 0; } ``` ## 感谢大家的观看,上方点赞哦!!