【算法學習】迴文樹

#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;
}
相關文章
相關標籤/搜索