【算法学习】回文树

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
struct PT{
	//回文树中每个节点表示一个回文串,所以有偶数长度的树和奇数长度的树两棵
	//next指针 next[u][i]表示u节点左右添加字符i之后得到的回文串节点
	int next[N][26];
	//fail指针 失配后跳转到最长后缀回文串对应的节点
	int fail[N];
	//节点对应回文串在原串中出现次数
	int cnt[N];
	//num[i]表示以节点i所表示的回文串右端点结尾的回文串个数(包括自身),即fail指针的深度
	int num[N];
	//节点对应回文串的长度
	int len[N];
	//存放添加的字符
	int S[N];
	//上一个字符所在节点
	int last;
	//字符数,不等于节点数
	int n;
	//回文树总结点数,包括奇偶两个空节点,节点编号为0到p-1
	int p;
	//初始化
	void init(){
		p=0;
		//奇偶空节点
		newnode(-1);
		newnode(0);
		last=0;
		n=0;
		S[n]=-1;
		//偶数根的fail指针是奇数根,奇数根的fail指针是本身
		fail[0]=1;
	}
	//创建长度为l的新节点
	int newnode(int l){
		for(int i=0;i<26;i++){
			next[p][i]=0;
		}
		cnt[p]=0;
		num[p]=0;
		len[p]=l;
		return p++;
	}
	//找到新插入字符c的回文匹配位置
	int getFail(int x){
		//在节点x对应串的后面加上一个字符,就判断x前面字符是否相同
		//若相同直接构成新的回文串,不同就跳到fail,即最长回文后缀
		//S[n-len[x]-1]就是新加的字符(S[n])关于x串的对称字符
		while(S[n-len[x]-1]!=S[n]){
			x=fail[x];
		}
		return x;
	}
	//插入字符c
	void add(int c){
		c-='a';
		S[++n]=c;
		//通过上一个回文串位置找到当前回文串匹配位置,也就是当前回文串节点的父节点
		int cur=getFail(last);
		if(!next[cur][c]){
			//出现了一个新的本质不同的回文串
			int now=newnode(len[cur]+2);
			//类似于AC自动机,往上跳直到找到满足条件的串节点
			fail[now]=next[getFail(fail[cur])][c];
			//fail指针深度加1
			num[now]=num[fail[now]]+1;
		}
		//最新回文串节点
		last=next[cur][c];
		cnt[last]++;
	}
	//统计每个节点回文串出现次数
	void count(){
		//从子节点逆推
		for(int i=p-1;i>=0;i--){
			//i节点出现,说明其最长回文后缀fail[i]也出现
			cnt[fail[i]]+=cnt[i];
		}
	}
}ac;
int main(void){
	return 0;
}
posted @ 2019-07-25 11:11  Keane1998  阅读(162)  评论(0编辑  收藏  举报