回文树(模板)

一、复杂度

    构造回文树需要的空间复杂度为O(N*字符集大小),时间复杂度为O(N*log(字符集大小))

二、应用

1、求串S前缀0~i内本质不同回文串的个数(两个串长度不同或者长度相同且至少有一个字符不同便是本质不同)

2、求串S内每一个本质不同回文串出现的次数

3、求串S内回文串的个数(其实就是1和2结合起来)

4、求以下标i结尾的回文串的个数

三、简单说明

int next[MAXN][26] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
     int fail[i] ;//fail指针,失配后跳转到fail指针指向的节点

     //回文树里面的一个节点就代表一个回文串

     int cnt[i] ;//表示第i个节点代表的回文串出现的次数
     int num[i] ; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。
     int leni[i] ;//表示第i个节点代表的回文串长度

     int S[i] ;//存放添加的字符
     int last ;//指向上一个字符所在的节点,方便下一次add
     int n ;//字符数组指针
     int p ;//节点指针

实现过程详解:

  https://www.cnblogs.com/crazyacking/p/4742400.html

四、代码

#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using namespace std;
const int MAXN = 100005 ;
const int N = 26 ;
char s[MAXN];//输入的要处理的字符串
struct Palindromic_Tree
{
     int next[MAXN][26] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
     int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点

     //回文树里面的一个节点就代表一个回文串

     int cnt[MAXN] ;//表示第i个节点代表的回文串出现的次数
     int num[MAXN] ; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。
     int len[MAXN] ;//表示第i个节点代表的回文串长度

     int S[MAXN] ;//存放添加的字符
     int last ;//指向上一个字符所在的节点,方便下一次add
     int n ;//字符数组指针
     int p ;//节点指针
     int newnode(int l)     //在树中新建节点
     {
           for(int i = 0 ; i < N ; ++ i) next[p][i] = 0 ;
           cnt[p] = 0 ;
           num[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 get_fail(int x)     //和KMP一样,失配后找一个尽量最长的
     {
          while(S[n - len[x] - 1] != S[n])
              x = fail[x] ;
          return x ;
     }
     void add(int c,int pos)
     {
           printf("%d:",p);
           c -= ‘a‘;
           S[++ n] = c ;
           int cur = get_fail(last) ;   //通过上一个回文串找这个回文串的匹配位置
           printf("%d ",cur);
           if(!next[cur][c])     //如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
           {
                 int now = newnode(len[cur] + 2) ;   //新建节点
                 fail[now] = next[get_fail(fail[cur])][c] ;   //和AC自动机一样建立fail指针,以便失配后跳转
                 next[cur][c] = now ;
                 num[now] = num[fail[now]] + 1 ;
                 for(int i=pos-len[now]+1; i<=pos; ++i)
                    printf("%c",s[i]);
           }
           last = next[cur][c] ;
           cnt[last] ++ ;
           putchar(10);
     }
     void count()
     {
           for(int i = p - 1 ; i >= 0 ; -- i)
                cnt[fail[i]] += cnt[i] ;
           //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
     }
} run;
int main()
{
     scanf("%s",&s);
     int n=strlen(s);
     run.init();
     for(int i=0; i<n; i++)
          run.add(s[i],i);
     run.count();
     return 0;
}

原文地址:https://www.cnblogs.com/-citywall123/p/11537444.html

时间: 2024-10-10 12:45:52

回文树(模板)的相关文章

HDU3948 &amp; 回文树模板

Description: 求本质不同回文子串的个数 Solution: 回文树模板,学一学贴一贴啊... Code: /*================================= # Created time: 2016-04-20 20:55 # Filename: hdu3948.cpp # Description: =================================*/ #define me AcrossTheSky&HalfSummer11 #include &l

回文树模板

存代码 学习的博客 然后国家集训队2017年的论文 在后面插入的 IL void Extend(RG int pos, RG int c){ RG int p = last; while(s[pos - len[p] - 1] != s[pos]) p = fa[p]; if(!son[c][p]){ RG int np = ++tot, q = fa[p]; while(s[pos - len[q] - 1] != s[pos]) q = fa[q]; len[np] = len[p] + 2

HYSBZ 3676 回文串 (回文树)

3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1680  Solved: 707 [Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的"出 现值"为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output

HYSBZ 2160 拉拉队排练(回文树)

2160: 拉拉队排练 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 825  Solved: 324 [Submit][Status][Discuss] Description 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛.所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要.拉拉队的选拔工作已经结束,在雨荨和校长的挑选下,n位集优秀的身材.舞

HDU.5394.Trie in Tina Town(回文树)

题目链接 \(Description\) 给定一棵\(Trie\).求\(Trie\)上所有回文串 长度乘以出现次数 的和.这里的回文串只能是从上到下的一条链. 节点数\(n\leq 2\times 10^6\),字符集为a,b,c,d. \(Solution\) 如果不是树,就是回文树模板.对于树,DFS \(x\)的每个儿子的时候都用在\(x\)处的\(las\)即可,也就是按深度存一个\(las\)数组,每次用\(las[dep-1]\)做\(las\)去插入即可.(也可以回溯的时候直接删

Palindromic Tree 回文自动机-回文树 例题+讲解

---恢复内容开始--- 回文树,也叫回文自动机,是2014年被西伯利亚民族发明的,其功能如下: 1.求前缀字符串中的本质不同的回文串种类 2.求每个本质不同回文串的个数 3.以下标i为结尾的回文串个数/种类 4.每个本质不同回文串包含的本质不同回文串种类 (本文参考自Palindromic Tree——回文树[处理一类回文串问题的强力工具],Palindromic Tree 回文自动机-回文树 解决回文串的神器) 下面介绍一些数组的意义 next[][]类似于字典树,指向当前字符串在两段同时加

P3649 [APIO2014]回文串(回文树)

题目描述 给你一个由小写拉丁字母组成的字符串 ss .我们定义 ss 的一个子串的存在值为这个子串在 ss 中出现的次数乘以这个子串的长度. 对于给你的这个字符串 ss ,求所有回文子串中的最大存在值. 输入输出格式 输入格式: 一行,一个由小写拉丁字母(a~z)组成的非空字符串 ss . 输出格式: 输出一个整数,表示所有回文子串中的最大存在值. 输入输出样例 输入样例#1: 复制 abacaba 输出样例#1: 复制 7 输入样例#2: 复制 www 输出样例#2: 复制 4 说明 [样例解

回文树总结

回文树介绍看这 : 点击 回文树 首先,回文树有何功能?假设我们有一个串S,S下标从0开始,则回文树能做到如下几点: 1.求串S前缀0~i内本质不同回文串的个数(两个串长度不同或者长度相同且至少有一个字符不同便是本质不同)2.求串S内每一个本质不同回文串出现的次数3.求串S内回文串的个数(其实就是1和2结合起来)4.求以下标i结尾的回文串的个数 模板: const int MAXN = 100005 ; const int N = 26 ; struct Palindromic_Tree { /

回文树

(没有坑怎么填?) 最近膜了一些关于回文串的题目,感到非常有意思,遂开篇记录. 在逛UOJ的题目时发现了vfk添上了新题,APIO 2014的题目.本身是一件很正常的事,而它事实上也没有变成什么了不得的事.我看到了Palindrome这个标题---回文串已经烂大街了,没什么新意.不过我很早就向学习回文树这东西了,久仰其大名而未尝真正去了结果它,于是我就顺手撸了一把豪哥的论文,发现他讲解的实在是晦涩难懂---论文的通病,就是虽然表述没有歧义,但是难以理解.嘛,然后我就找了几个标程,发现回文树这东西