洛谷
BZOJ权限题spa
若是要咱们作暴力,显然能够以某个点为根节点,而后把子树\(dfs\)一遍,建出特征串的\(SAM\),就能够直接计算出现次数了。复杂度是\(O(size^2)\)
另一种暴力是咱们枚举以某个点为中心,考虑在其两棵不一样子树内各选择一条链,而后拼接在一块儿计算答案。咱们假设选择了\(R\)为中心,而后有一条\((u\rightarrow R)\)的链,有一条\((R\rightarrow v)\)的链,咱们把\((u\rightarrow R)\)这个串在每一个匹配到的结尾位置打上一个标记,把\((R\rightarrow v)\)这个串在每一个被匹配到的开头位置打上一个标记,因而咱们就只须要把每一个位置的左右两个标记乘起来就是答案了。
而后考虑怎么打这个标记,对于在开头位置打标记,显然是匹配上了一个后缀的前缀,那么咱们把后缀树建出来,由于每个后缀上的一个叶子节点对应着一个后缀,这样子咱们只要在后缀树上找到这个串匹配的节点,而后其子树的全部叶子节点对应的后缀的开头位置都要\(+1\),因而子树加能够变成在后缀树上的匹配点单点加,最后一次\(dfs\)一次后缀树就行了。相似的,在结尾位置打标记就是在前缀的一段后缀打标记,那么建出前缀树就好了。因而咱们就能够作到\(O(m+size)\),其中\(m\)是特征串的长度。可是这样子会出现\(R\)的相同子树里的一个从上往下的串和一个从下往上的串进行了匹配,因而咱们还要对于每个子树进行去除。
如今有了这两种复杂度不一样的作法,显然咱们能够按照\(B=\sqrt m\)来分类讨论,对于\(size\le B\)直接\(O(size^2)\)暴力,不然对应下面这种的\(O(m+size)\)的作法,注意对于容斥减去相同子树内的贡献的时候,也须要考虑使用两种对应的方法,不然复杂度是假的。
upd:
补一下关于复杂度的证实:
对于第一类暴力,单次是\(O(size^2)\)的,由于这样处理完以后全部子树的答案已经贡献完毕,能够直接返回,因此只须要在分治子树大小第一次小于\(B\)的时候统计答案,而后由于全部这样的子树两两不交,因此\(\sum size\)是不会超过\(n\)的,而\(\sum size^2\le \frac{n}{B}B^2=nB\),因此这一部分的复杂度是\(O(nB)\)的。
对于第二类暴力,咱们考虑\(size\gt B\)的分治重心的个数,根据点分治的性质,没有子树的\(size\)会大于父亲的一半,因此每次向上至少要合并两个\(size\gt B\)的分治子树,而这样子的子树不会超过$ \frac{n}{B}\(个,因此向上合并的次数不会超过\)\frac{n}{B}$次,因此这样子的分治重心的个数不会超过\(2\frac{n}{B}\),而这样子单次复杂度是\(O(size+m)\),因此这部分的总复杂度是\(O(\frac{n}{B}m)\)。
综上\(\frac{n}{B}m=nB\),即\(B=\sqrt m\)的时候复杂度最优,为\(O((n+m)\sqrt m)\)。get
代码被我咕咕咕了怎么办......class