回文树

回文树是一个很方便的解决回文串的问题。
他可以求出本质不同的回文串个数。
它的处理方式是这样:
每次一个一个加入,每次加入字符的时候计算个数。
它对每个回文串都存储了一个结点,属性为长度。通过每个回文串,以一条字母边可以指向新的回文串,新的回文串=旧的回文串在两侧加上该字母。
每次找到当前字母结尾的最长的且能够满足新加入的字母和最边缘的字母(该回文串签一个字母)相同的最长回文串。寻找的过程是跳fail指针的过程。
如果该回文串通过该字母产生的新回文串被记录过了,那么不再记录。

如何快速找到上次加入字母过后的最长回文串,显然是上次找到或创建的新回文串。所以我们记录下上次的回文串。找的时候不断跳fail指针即可。
fail指针怎么建立呢?

每次创建新的回文串:新的回文串的fail指针指向自己的最长回文后缀。

但是算法的正确性我无法理解。[所以现在只能记住。想了快十个小时了,还是想不明白。
模板如下:

struct PAM{
    int Next[maxn][sigma_size],fail[maxn],len[maxn],S[maxn];
    int last,n,p;
    ll ans=0;

    int Newnode(int x){
        for(int i=0;i<sigma_size;i++)Next[p][i]=0;
        len[p]=x;
        return p++;
    }

    void init(){
        p=0,ans=0;
        Newnode(0);Newnode(-1);
        last=0,n=0;
        S[n]=-1;fail[0]=1;
    }

    int get_fail(int x){
        while(S[n-len[x]-1]!=S[n])x=fail[x];
        return x;
    }

    void insert(int c){
        S[++n]=c;
        int cur=get_fail(last);
        if(!Next[cur][c]){
            int now=Newnode(len[cur]+2);
            //在这里进行计算:唯一子串只会出现一次
            fail[now]=Next[get_fail(fail[cur])][c];
            Next[cur][c]=now;
        }
        last=Next[cur][c];
    }
}pm;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值