对AC自动机的深层次的理解
题目链接:bzoj 2434
题意:写 B z o j 的题意就是简单——题意见上……
题解:这个题本质就是在问:给定一棵 Trie 树,询问根到 X 的字符串在根到 Y 的字符串中出现了多少次。而 X 在 Y 中出现(即是 Y 的一个子串),必定是 Y 的一个前缀的后缀。在 Trie 树中根到 Y 的路径上的点都是 Y 的前缀。在 Fail 树中根到点 P 的路径上的点都是 P 的后缀。离线做法,在 Trie 树上 DFS ,维护 Fail 树的 DFS 序列。根到 Trie 树上当前点的所有点沿 Fail 树到根的路径权值 +1。Fail 树到根的路径上的权值 +1,询问 Fail 树上的一个点权值,可以转化为点的权值 +1,询问子树内权值和。
我思故我在:通过这道题给我最大的启示是:Fail 指针的含义,对于一个串 X,即在所有的串中找到一个最长的前缀等于 X 的后缀(类似 Next 数组,但是并不一样)。又因为对于一个完整的字符串,它一定是 Trie 树上的一个前缀。所以如果我们不断的走一个前缀的 Fail 指针,那么我们将遍历到所有的对于它来说有价值的后缀。第二点,我发现我对于这道题所谓的离线理解并不正确。一开始我以为离线就是以 Y 串对 X 串进行分组,然后一个 Y 一个 Y 的进行 DFS 并维护树状数组。实则不然,这个题所谓的离线是指在建完AC自动机并维护完 DFS 序后,再次将读入都读进来一遍,然后一边读入、一边维护树状数组。原题中的三个操作就变成了在树状数组上插入、删除和查询的操作。