回文树学习笔记

回文树


tags:字符串

学习博客:https://blog.csdn.net/dacc123/article/details/51556837

一、概述

struct PAM
{
	int fail[N],ch[N][26],len[N],nod,lst;
	void init() {fail[0]=fail[1]=nod=1;len[1]=-1;}
	void extend(int c,int i,char *s)
		{
			int p=lst;
			while(s[i-len[p]-1]!=s[i]) p=fail[p];
			if(ch[p][c]) {lst=ch[p][c];return;}
			int x=++nod,k=fail[p];
			while(s[i-len[k]-1]!=s[i]) k=fail[k];
			fail[x]=ch[k][c];len[x]=len[p]+2;
			lst=ch[p][c]=x;
		}
};

回文树中每个节点表示以它结尾的最长回文后缀

其中0号点表示长度为0,1号点表示长度为-1,分别匹配偶回文和奇回文

(len)表示该回文后缀的长度,(fa)表示其(fail)——这个回文后缀的最长回文后缀

复杂度(O(n))

二、作用&性质

  • 1.本质不同的回文串种数以及个数

回文串种数即nod的大小
每次extend后最后所在的点加1,则其fail链上的点都加1,即可算出某串的个数

  • 2.以某点结尾的回文串个数(把串反过来就是以其开头的)

就是该位置所代表的点的fail链深度

  • 3.前后加字符,动态构串
void extend(int c,int i,int &lst,int op)
{
	int p=lst;
	while(s[i-op*len[p]-op]!=s[i]) p=fail[p];
	if(!ch[p][c])
	{
		int x=++nod,k=fail[p];
		while(s[i-op*len[k]-op]!=s[i]) k=fail[k];
		len[x]=len[p]+2;
		fail[x]=ch[k][c];
		dep[x]=dep[fail[x]]+1;
		ch[p][c]=x;
	}
	lst=ch[p][c];ans+=dep[lst];
	if(len[lst]==r-l+1) pre=suf=lst;
}
  • 4.fail链上最长回文后缀长度等差
void extend(int c,int i)
{
	int p=lst;
	while(s[i]!=s[i-len[p]-1]) p=fail[p];
	if(!ch[p][c])
	{
		int x=++nod,k=fail[p];
		while(s[i]!=s[i-len[k]-1]) k=fail[k];
		len[x]=len[p]+2;
		fail[x]=ch[k][c];
		ch[p][c]=x;
		diff[x]=len[x]-len[fail[x]];
		anc[x]=(diff[x]==diff[fail[x]])?anc[fail[x]]:fail[x];
	}
	lst=ch[p][c];
}

例题:https://www.cnblogs.com/cjyyb/p/8462865.html

三、完成了一些题目

  • [HDU5421]Victor and String
  • [Codeforces17E]Palisection
  • [国家集训队]最长双回文串
  • yyb 12.21 T2
原文地址:https://www.cnblogs.com/xzyxzy/p/10171491.html