【算法学习】回文树

#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;
        fail[1]=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;
}

猜你喜欢

转载自www.cnblogs.com/zxcoder/p/11242979.html