回文树介绍

回文树例题看这 : 点击

简介


  咱们知道,Manacher算法能够在[Math Processing Error]O(n)的时间内求出以每一个位置为中心的最长回文串(虽然我昨天还不知道Manacher算法是怎么作的)。可是若是要统计回文串的个数,Manacher就捉襟见肘了。因而,回文自动机闪亮登场!
  回文自动机是解决回文串问题的一类数据结构。
  这个数据结构比较新,是由来自战斗民族的MikhailRubinchik在2014年的Petrozavodsk夏令营提出。(http://codeforces.com/blog/entry/13959)
  回文树实际上是两棵树,分别是偶数长度的回文树和奇数长度的回文树,树中每个节点表明一个回文串。
  而回文自动机的方法与Manacher迥乎不一样,反倒与KMP和AC自动机相似,因此若是你不会Manacher,也没必要像我同样去学。html

 

前置技能


  KMP、AC自动机。算法

数听说明


len[i]:节点i的回文串的长度
next[i][c]:节点i的回文串在两边添加字符c之后变成的回文串的编号(和字典树的next指针相似)
fail[i]:相似于AC自动机的fail指针,指向失配后须要跳转到的节点(即为i的最长回文后缀且不为i)
cnt[i]:节点i表示的回文串在S中出现的次数(建树时求出的不是彻底的,count()加上子节点之后才是正确的)
num[i]:以节点i回文串的末尾字符结尾的但不包含本条路径上的回文串的数目。(也就是fail指针路径的深度)
last:指向以字符串中上一个位置结尾的回文串
cur: 指向由next构成的树中当前回文串的父亲节点(即当前回文串是cur左右两边各拓展一个字符得来)
S[i]:第i次添加的字符
p:添加的节点个数
n:添加的字符个数数据结构

分析


  假设如今咱们有串S=’abbaabba’。
  先建两个树根,偶数长度的根为0,奇数长度的根为1。注意,咱们将len[0]设为0,但将len[1]设为-1。将p、n、last均初始化为0。将S[0]设为-1,这是放一个字符集中没有的字符,减小特判。而后,咱们将fail[0]指向1。
  举个例子,如有串S=’abbaabba’。
  首先咱们添加第一个字符’a’,S[++ n] = ‘a’,而后将cur赋为get_fail(last)。其中的get_fail函数就是让找到第一个使得S[n-len[last]-1]==S[n]的last。注意,此处的n不为get_fail中的参数,依然为添加的字符个数。这样作的话,咱们就能够经过fail构成的失配链找到last的全部回文后缀(包括它本身),而后从长到短依次判断此后缀的前一位是否等于S[n],等于则代表能够构成一个回文串。
  判断此时next[cur][‘a’]是否已经有后继,若是next[cur][‘a’]没有后继,咱们就进行以下的步骤:
  新建节点(节点数p++,且以后p=3),并让now等于新节点的编号(now=2),则len[now]=len[cur]+2(每个回文串的长度老是在其最长子回文串的基础上在两边加上两个相同的字符构成的,因此是+2,同时体现出咱们让len[1]=-1的优点,一个字符自成一个奇回文串时回文串的长度为(-1)+2=1)。
  而后咱们让fail[now]=next[get_fail ( fail[cur] )][‘a’],即获得fail[now](此时为fail[2] = 0)。计算get_fail(fail[cur])是为了求出在cur的全部回文后缀中(不包括它本身,由于和AC自动机同样,fail[now]不能指向now),知足前一位等于S[n]的后缀,咱们便可用它来往两边拓展一格,即为now的最长回文后缀(不包括它本身)。而后next[cur][‘a’] = now。
  当上面步骤完成后咱们让last = next[cur][‘a’](无论next[cur][‘a’]是否有后继),而后cnt[last] ++。
  如上述方法插完全部字符后,咱们将节点x在fail指针树中将本身的cnt累加给父亲,从叶子开始倒着加,最后就能获得串S中出现的每个本质不一样(两个串长度不一样或者长度相同且至少有一个字符不一样即是本质不一样可使用burnside引理)回文串的个数。
  构造回文树须要的空间复杂度为[Math Processing Error]O(N∗字符集大小),时间复杂度为O[Math Processing Error](N∗log(字符集大小)),这个时间复杂度比较神奇。若是空间需求太大,能够改为邻接表的形式存储,不过相应的要牺牲一些时间。ide

功能

求串S前缀0~i内本质不一样回文串的个数
求串S内每个本质不一样回文串出现的次数
求串S内回文串的个数(其实就是1和2结合起来)
求如下标i结尾的回文串的个数

函数

相关文章
相关标签/搜索