1.回文树的next[charset]指针:
b->aba
那么就这样表示:b.next[a]=aba
当然树里面肯定不能存字符串,于是就直接用下标标号代替了
2.回文树的fail指针:
跟ac自动机类似,fail指针指向当前节点的最大回文后缀
没有就指向根
3.回文树的根
有2个根,一个单根就是往下连回文串长度为奇数的节点,本身长度为-1
还有个双根就是往下连回文串长度为偶数的节点,本身长度为0
双根的fail指向单根
当然,也可以像manacher那样,aab->&a&a&b&,这样只用单根就是一棵树了。
可以树DP或者可持久化什么的。。。
4.回文树节点的域
len->表示当前节点回文串的长度,一般做回文串长度的题会用
cnt->表示当前节点被插入过多少次,一般做计数类的题会用,一般需要配合count函数
代码模板:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=100005;
const int N=26;
struct Palindromic_Tree{int next[MAXN][N],fail[MAXN],cnt[MAXN],len[MAXN],S[MAXN],last,n,p;int newnode(int l){for(int i=0;i<N;++i)next[p][i]=0;cnt[p]=0;len[p]=l;return p++;}void init(){p=0;newnode(0);newnode(-1);last=0;n=0;S[n]=-1;fail[0]=1;}int getfail(int x){while(S[n-len[x]-1]!=S[n])x=fail[x];return x;}void insert(int c){c-='a';S[++n]=c;int cur=getfail(last);if(!next[cur][c]){int now=newnode(len[cur]+2);fail[now]=next[getfail(fail[cur])][c];next[cur][c]=now;}last=next[cur][c];++cnt[last];}void count(){for(int i=p-1;i>=0;--i)cnt[fail[i]]+=cnt[i];}
}pt;
char s[MAXN];
int main()
{scanf("%s",s);int n=strlen(s);pt.init();for(int i=0;i<n;i++)pt.insert(s[i]);pt.count();for(int i=0;i<pt.p;++i)printf("%d\n",pt.cnt[i]);
}

下面说说用这个模板怎么做回文树的题:
1.最长回文子串

for(int i=0;i<pt.p;++i)ans=max(ans,pt.len[i]);

很简单吧,如果要输出的话还要保存插入进去的字符的下标。
但是一般用manacher写这个题会更简单。
2.求字符串中有多少个本质不同的回文子串
例如abad,本质不同的回文字串有:a,b,d,aba,共4个。

ans=pt.p-2;

很简单吧,其实就是看看回文树里面除了根以外有几个节点。
3.对于一个空字符串s,每次在s末尾加上一个字符,对于每次操作,求字符串中有多少个本质不同的回文子串
其实跟上面代码一样。。每插入一次就算一次ans。提出这个只是为了说明回文树是动态的。当然,如果这个s支持删除操作那么应该会用到可持久化回文树。删除就得回到之前的版本。
4.求字符串每个回文子串出现过多少次
例如abad,本质不同的回文字串有:a,b,d,aba,共4个。
a出现过2次。
b出现过1次。
d出现过1次。
aba出现过1次。
终于用到cnt数组了。
上面那个模板其实就是解决这个问题的。
就是非常简单的树DP

void count()
{for(int i=p-1;i>=0;--i)cnt[fail[i]]+=cnt[i];
}

因为i这个节点的fail[i]就是i的最长回文后缀
假设i出现过cnt[i]次,那么fail[i]除了它自己出现cnt[fail[i]]次,还在i中出现了cnt[i]次。并且还要倒着从叶子节点往根推。
最后要输出答案的话,一般还是要保存下标
根据下标和回文串长度来按题意顺序输出cnt
5.求字符串中回文串的个数
例如abad。a出现过2次。b出现过1次。d出现过1次。aba出现过1次。
因此回文串有5个。
可以发现的是,刚才的树DP已经推到根了,那么根的cnt值就是答案。因为两个根之间有fail关系所以输出哪个根的cnt都可以。
6.求两个字符串的公共回文串的个数(2014-2015 ACM-ICPC, Asia Xian Regional Contest)
建两棵回文树,分别insert两个字符串。
然后分别从2个根开始沿着next数组下去dfs。
如果treea.next[cura][i] 和treeb.next[curb][i] 都存在
那么说明两个字符串都有相同的回文串,于是

cura=treea.next[cura][i];
curb=treeb.next[curb][i];
ans+=treea.cnt[cura]*treeb.cnt[curb];

然后递归下一层dfs(cura,curb);。
如果treea.next[cura][i] 和treeb.next[curb][i] 有一个不存在就不往下dfs了。
7.BZOJ 2565 最长双回文串
给出一个字符串,求所有子串中能分成前后两个部分都是回文串最长的子串的长度。
问题实际上是求两个这样的数组left[],right[],分别表示以某位置结尾往左或往右最长的回文子串。
这个怎么搞?
就是给出一个空字符串s,每次往s的末尾加一个字符,然后查询s里面包含末尾字符的最长的回文子串的长度。修改一下insert函数:

int insert(int c)
{c-='a';S[++n]=c;int cur=getfail(last);if(!next[cur][c]){int now=newnode(len[cur]+2);fail[now]=next[getfail(fail[cur])][c];next[cur][c]=now;}last=next[cur][c];++cnt[last];return len[last];
}

insert函数的返回值就是要求的。
如果从左往右加字符,得到的结果就是left[],如果从右往左加字符,得到的就是right[]。然后枚举中间点,答案是left[i]+right[i],就可以找最大值。
所以需要2棵回文树(当然一棵用完了初始化再用一次也可以的)。

转载于:https://www.cnblogs.com/geng4512/p/5296880.html

回文树笔记(转自quack_quack)相关推荐

  1. 「学习笔记」回文树/回文自动机(Palindromic Tree)

    引入 有时候题目要求一些这样的问题 1. 求以串 s s s 本质不同的回文串个数(即长度不同或长度相同且至少有一个字符不相同的字符串) 2. 求以位置i" role="prese ...

  2. 回文树 PAM 学习笔记

    摘自 <2017 年国家集训队论文>" 回文树及其应用 " 一些规定 :Σ\SigmaΣ 表示字符集大小 串 SSS 和字符 ccc,用 ScScSc 表示将 ccc ...

  3. 2014-2015 ACM-ICPC, Asia Xian Regional Contest G The Problem to Slow Down You 回文树

    The Problem to Slow Down You Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjud ...

  4. 回文树(回文自动机) - URAL 1960 Palindromes and Super Abilities

     Palindromes and Super Abilities Problem's Link:  http://acm.timus.ru/problem.aspx?space=1&num=1 ...

  5. 回文树或者回文自动机,及相关例题

    回文树简述 在大部分说法中,回文树与回文自动机指的是一个东西: 回文树是对一个字符串,基于自动机思想构建的处理回文问题的树形结构: 回文树是对着一个单串建立的: 于是他主要用于计数(回文子串种类及个数 ...

  6. BZOJ2565 最长双回文子串 回文自动机,回文树

    bzoj2565: 最长双回文串 题意 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba" ...

  7. HDU 5157(回文树)

    传送门 题面: Harry got a string T, he wanted to know the number of T's disjoint palindrome substring pair ...

  8. 【BZOJ2565】最长双回文串(回文树)

    [BZOJ2565]最长双回文串(回文树) 题面 BZOJ 题解 枚举断点\(i\) 显然的,我们要求的就是以\(i\)结尾的最长回文后缀的长度 再加上以\(i+1\)开头的最长回文前缀的长度 至于最 ...

  9. 回文树 / 自动机模板

    const int maxn = 400000; const int N = 26 ;struct Palindromic_Tree {int next[maxn][N] ;//next指针,next ...

最新文章

  1. 谷歌推出TFQ,一个可训练量子模型的机器学习框架
  2. java翻译smali,请各位好人帮我翻译Java成smali(没有false)
  3. 自定义镜像-镜像结构
  4. OpenBase关于一致性,可用性,分区容错性(CAP)分析
  5. 我是最棒的,我一定会成功!
  6. 工作113:声明问题 的定义变量
  7. java内存shell_Springboot 内存shell
  8. html5元件的作用,寄存器的作用是什么
  9. 【C++面向对象】类的大小以及虚继承
  10. leetcode题解200-岛屿数量
  11. 安装ISE.14.7后仿真时遇到的问题与解决
  12. 怎样维系和监督多项计划
  13. 【接口文档】微信支付现金红包未开通,公众号发红包用第三方红包代发接口
  14. python图案绘制解锁_PythonAppium实现安卓手机图形解锁详解
  15. The alias ‘TaskType‘ is already mapped to the value ‘com.xxx.entity.Tasktype‘.
  16. 第23天:如何使用带有哈利·波特PortKey的ARKit和Unity构建应用程序
  17. windows安装软件出现“command line option syntax error”错误
  18. latex图片排版技巧总结
  19. php+挖矿病毒,Kdevtmpfsi 挖矿病毒处理方式
  20. 《DFQ》开发随录——后记

热门文章

  1. WinForm中的各种对话框
  2. PKU A Simple Problem with Integers 3468
  3. Python 越来越火,为什么?
  4. 不用虚拟机直接在线用的 Linux,统统都在这里!
  5. java jtable应用源码_JTable的应用(一)
  6. sql语句使用foreach报错
  7. Docker日志日期时间精确查询
  8. mysql登陆salt_salt把返回写入到mysql
  9. mysql 5.5.15_mysql5.5.15配置主从数据库
  10. 接口调试利器:Postman