回文树

2024-08-13

通过奇偶字典树和后缀链跳跃实现回文数,统计字符串中的回文串个数

#include <bits/stdc++.h>
#define io cin.tie(0), cout.tie(0), ios::sync_with_stdio(false)
#define LL long long
#define ULL unsigned long long
#define EPS 1e-8
#define INF 0x7fffffff
#define SUB -INF - 1
using namespace std;
const int N = 300008;
int s[N];
struct node
{
    int len, fail, son[26], size;
    void init(int _len)
    {
        memset(son, 0, sizeof(son));
        fail = size = 0;
        len = _len;
    }
} tree[N];
LL num, last[2], ans, l, r;
void init()
{
    last[0] = last[1] = 0;
    ans = 0;
    num = 1;
    l = 100008, r = 100007;
    tree[0].init(0);
    memset(s, -1, sizeof(s));
    tree[1].init(-1);
    tree[0].fail = 1;
}
int getFail(int p, int d)
{
    if (d)
        while (s[r - tree[p].len - 1] != s[r])
            p = tree[p].fail;
    else
        while (s[l + tree[p].len + 1] != s[l])
            p = tree[p].fail;
    return p;
}
void Insert(int x, int d)
{
    if (d)
        s[++r] = x;
    else
        s[--l] = x;
    int father = getFail(last[d], d);
    int now = tree[father].son[x];
    if (!now)
    {
        now = ++num;
        tree[now].init(tree[father].len + 2);
        tree[now].fail = tree[getFail(tree[father].fail, d)].son[x];
        tree[now].size = tree[tree[now].fail].size + 1;
        tree[father].son[x] = now;
    }
    last[d] = now;
    if (r - l + 1 == tree[now].len)
        last[d ^ 1] = now;
    ans += tree[now].size;
}
int main()
{
    int op, n;
    while (scanf("%d", &n) != EOF)
    {
        init();
        while (n--)
        {
            char c;
            scanf("%d", &op);
            if (op == 1)
            {
                getchar();
                scanf("%c", &c);
                Insert(c - 'a', 0);
            }
            if (op == 2)
            {
                getchar();
                scanf("%c", &c);
                Insert(c - 'a', 1);
            }
            if (op == 3)
                printf("%lld\n", num - 1);
            if (op == 4)
                printf("%lld\n", ans);
        }
    }
    return 0;
}