Cool。。
Link
(权限题。。一开始用小号交的时候显示:Where do find this link?No such problem.我就不说什么了。)
Description
Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P。 “2 x”,Alice询问Bob,集合T中有多少个字符串包含串S_x。(我们称串A包含串B,当且仅当B是A的子串) Bob遇到了困难,需要你的帮助。
Solution
嗯。。寻找集合中有多少串包含,可以用Fail树做。 于是就把询问离线,把的字符串扔到一个Trie里然后跑出来AC自动机。建立了Fail树,对于一个询问,就转化为查询Fail树,的末尾节点对应节点的子树中,存在多少表示中在此查询之前插入的串的节点,可以用线段树维护。 在建立AC自动机的时候,在Trie的每个节点记录有多少串包含了这个节点, 然后一遍DFS,加上线段树合并的复杂度,总共是。 写完之后交上去居然1A了。。 虽然这么暴力但跑的也不是很慢,11s。重载operator new之后快了1s。。只是内存占用超级大。。500M。。
正解
对建立AC自动机,建立Fail树。每个节点维护一个值,记录子树下有多少个T。 对于中的新串在AC自动机上跑,记录到达的节点。然后把Fail树中这些节点的值+1,把相邻点的LCA的值-1。查询就是子树和了。Orz。。又快又好写。。
Tips
只想出暴力离线的做法还是因为学得有些死板。一个串在AC自动机上跑到的节点,和在AC自动机上串的节点的性质其实是差不多的。
Code(新代码风格,欢迎拍砖吐槽)
1 | //Code by Lucida |