后缀自动机

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 = 2007;
int sz, last;
struct Node
{
    int son[26];
    int father;
    int len;
} t[N << 1];
void newNode(int length)
{
    t[++sz].len = length;
    t[sz].father = -1;
    memset(t[sz].son, 0, sizeof(t[sz].son));
}
void init()
{
    sz = -1;
    last = 0;
    newNode(0);
}
void Insert(int c)
{
    newNode(t[last].len + 1);
    int p = last, cur = sz;
    while (p != -1 && !t[p].son[c])
        t[p].son[c] = cur, p = t[p].father;
    if (p == -1)
        t[cur].father = 0;
    else
    {
        int q = t[p].son[c];
        if (t[q].len == t[p].len + 1)
            t[cur].father = q;
        else
        {
            newNode(t[p].len + 1);
            int nq = sz;
            memcpy(t[nq].son, t[q].son, sizeof(t[q].son));
            t[nq].father = t[q].father;
            t[cur].father = t[q].father = nq;
            while (p >= 0 && t[p].son[c] == q)
                t[p].son[c] = nq, p = t[p].father;
        }
    }
    last = cur;
}
char S[N];
int ans[N][N];
int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%s", S);
        int n = strlen(S);
        for (int i = 0; i < n; i++)
        {
            init();
            for (int j = i; j < n; j++)
            {
                Insert(S[j] - 'a');
                ans[i][j] = ans[i][j - 1] + t[last].len - t[t[last].father].len;
            }
        }
        int q, l, r;
        scanf("%d", &q);
        while (q--)
        {
            scanf("%d%d", &l, &r);
            printf("%d\n", ans[--l][--r]);
        }
    }
    return 0;
}