博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
回文树模板
阅读量:6495 次
发布时间:2019-06-24

本文共 3434 字,大约阅读时间需要 11 分钟。

存代码

然后国家集训队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, fa[np] = son[c][q];        son[c][p] = np;    }    last = son[c][p], ++size[last];}

支持前后插入,维护最长回文前缀和最长回文后缀

前缀的\(fail\)和后缀的\(fail\)相同,因为回文串的对称性
题目

# include 
# define IL inline# define RG register# define Fill(a, b) memset(a, b, sizeof(a))using namespace std;typedef long long ll;IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z;}const int maxn(1e5 + 5);int n, tot, prel, sufl, son[26][maxn], len[maxn], deep[maxn], fa[maxn], l, r;ll ans;char s[maxn << 1];IL void Init(){ for(RG int i = l; i <= r; ++i) s[i] = 'z' + 1; for(RG int i = 0; i <= tot; ++i){ len[i] = deep[i] = fa[i] = 0; for(RG int j = 0; j < 26; ++j) son[j][i] = 0; } prel = sufl = 0, tot = 1, fa[1] = fa[0] = 1, len[1] = -1;}IL void Extend(RG int pos, RG int c, RG int &last, RG int op){ RG int p = last; while(s[pos - op * (len[p] + 1)] != s[pos]) p = fa[p]; if(!son[c][p]){ RG int np = ++tot, q = fa[p]; while(s[pos - op * (len[q] + 1)] != s[pos]) q = fa[q]; len[np] = len[p] + 2, fa[np] = son[c][q]; son[c][p] = np; } last = son[c][p], deep[last] = deep[fa[last]] + 1, ans += deep[last]; if(len[last] == r - l + 1) prel = sufl = last;}int main(){ while(scanf("%d", &n) != EOF){ Init(), l = 1e5, r = l - 1, ans = 0; for(RG int i = 1; i <= n; ++i){ RG int op = Input(); if(op <= 2){ RG char c; scanf(" %c", &c); if(op == 1) s[--l] = c, Extend(l, c - 'a', prel, -1); else s[++r] = c, Extend(r, c - 'a', sufl, 1); } else printf("%lld\n", op == 3 ? tot - 1 : ans); } } return 0;}

求回文子串个数

如果是本质不同的,即就是回文树的点数减去两个根

否则就是 \(fail\) 树上的 \(deep\) 和也就是 \(size\)这两个显然相等

一个点的 \(deep\) 表示以这个点包含的端点集合为右端点的回文串的个数

一个点的 \(size\) 表示这个点表示的回文串出现的端点集合大小

# include 
# define IL inline# define RG register# define Fill(a, b) memset(a, b, sizeof(a))using namespace std;typedef long long ll;IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z;}const int maxn(1005);int fa[maxn], num[maxn], len[maxn], son[26][maxn], ans, n, tot, last;char s[maxn];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 q = fa[p], np = ++tot; while(s[pos - len[q] - 1] != s[pos]) q = fa[q]; fa[np] = son[c][q]; son[c][p] = np, len[np] = len[p] + 2; } last = son[c][p], ++num[last];}int main(){ scanf(" %s", s + 1), n = strlen(s + 1); tot = 1, len[1] = -1, fa[0] = fa[1] = 1; for(RG int i = 1; i <= n; ++i) Extend(i, s[i] - 'a'); for(RG int i = tot; i; --i) num[fa[i]] += num[i]; for(RG int i = 2; i <= tot; ++i) ans += num[i]; printf("%d\n", ans); return 0;}

字符集大时\(map\)

卡空间时邻接表

转载于:https://www.cnblogs.com/cjoieryl/p/9153189.html

你可能感兴趣的文章
WP8:Unity3D之间的值传递
查看>>
string与数值之间的转换
查看>>
Windows系统安装Oracle 11g客户端
查看>>
怎样写出一个较好的高速排序程序
查看>>
【动态规划】最长公共子序列与最长公共子串
查看>>
要立刷金组flag了T_T
查看>>
Swift常量和变量
查看>>
GNU Make chapter 2 —— Makefile 介绍
查看>>
[转]在Eclipse中使用JUnit4进行单元测试(中级篇)
查看>>
gdb图形化调试工具总结
查看>>
白话经典算法系列之七 堆与堆排序
查看>>
微软职位内部推荐-SDEII
查看>>
Windows下FFmpeg高速入门
查看>>
【分享】 IT囧事
查看>>
Android安卓开发中图片缩放讲解
查看>>
【Java】Lucene检索引擎详解
查看>>
Cts框架解析(7)-任务运行的调度室
查看>>
SDN:软件定义网络
查看>>
1.1GTK+ 的简单程序HelloWorld
查看>>
一款基jquery超炫的动画导航菜单
查看>>