回文树模板(不太好理解)

这个算法又花了六七个小时,不能说完全掌握了,只能说原理基本上懂了,模板基本上也懂了,还要很多地方需要去琢磨。。

这个知识点可以看视频,我推荐的是b站的–》Clever_jimmy ,这个作者讲的很好

模板题:https://acm.hdu.edu.cn/showproblem.php?pid=5658

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;

#define MAXN 1010

struct palindromic_tree{

    int next[MAXN][26]; //表示编号i的节点表示的回文串在两边添加字符c以后变成的回文串的编号
    int len[MAXN];      //表示编号i的节点表示的回文串长度
    int fail[MAXN];     //表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文字符串
    int cnt[MAXN];      //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的
    int num[MAXN];      //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
    int s[MAXN];        //表示第i次添加的字符
    int last;           //指向新添加一个字母后所形成的最长回文串表示的节点
    int n,p;            //n表示添加的字符个数,p表示添加的节点数

    int newNode(int k){

        for(int i = 0;i<26;i++) next[p][i] = 0;
        cnt[p] = 0;
        num[p] = 0;
        len[p] = k;
        
        return p++;
    }

    void init(){
        memset(next,0,sizeof(next));
        p = 0;          
        newNode(0);     //偶数根
        newNode(-1);    //奇数根
        last = 0;
        n = 0;
        s[n] = -1;
        fail[n] = 1;
    }

    int get_fail(int x){

        while(s[n - len[x] - 1] != s[n]) x = fail[x];
        return x;
    }

    void add(int c){
        c = c - 'a';
        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;
            num[Now] = num[fail[Now]] + 1;
        }
        last = next[cur][c];
        cnt[last]++;
    }

    void Count(){
        for(int i = p-1;i>=0;i++)
            cnt[fail[i]] += cnt[i];
    }

}tree;

char str[MAXN];
int sum[MAXN][MAXN];

int main(){

    int t;
    scanf("%d",&t);
    while(t--){

        int ans = 0;
        scanf("%s",str);
        int len1 = strlen(str);

        for(int i = 0;i<len1;i++){
            tree.init();
            for(int j = i;j<len1;j++){
                tree.add(str[j]);
                sum[i+1][j+1] = tree.p - 2;
            }
        }

        int q;
        int l,r;
        scanf("%d",&q);
        while(q--){
            scanf("%d%d",&l,&r);
            printf("%d\n",sum[l][r]);
        }
    }

    
    // system("pause");
    return 0;
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值