SPOJ 8222 Substrings

题面

Description

给长度为 n 的字符串 S , 对任意的 L , 求长度为 L 的子串最多出现的次数.

Input

String S consists of at most 250000 lowercase latin letters.

Output

Output |S| lines. On the i-th line output F(i).

Sample Input

ababa
Sample Output
3
2
2
1
1

题解

后缀自动机统计子串出现次数的应用.
考虑我们插入一个节点时, 其suffix link上的所有节点所代表的字符串的出现次数都+1, 因此parent tree上一个节点所代表的字符串的出现次数等于以它为根的子树中实点的出现次数.
线段树上成段更新来维护即可.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

const int LEN = 250000;

struct segmentTree
{
    int a[LEN << 2];

    inline segmentTree()
    {
        memset(a, 0, sizeof(a));
    }

    void modify(int u, int curL, int curR, int L, int R, int w)
    {
        if(curL >= L && curR <= R)
        {
            a[u] = std::max(a[u], w);
            return;
        }
        int mid = curL + curR >> 1;
        if(L <= mid)
            modify(u << 1, curL, mid, L, R, w);
        if(R > mid)
            modify(u << 1 | 1, mid + 1, curR, L, R, w);
    }

    inline void modify(int L, int R, int w)
    {
        modify(1, 1, LEN, L, R, w);
    }

    int query(int u, int L, int R, int pos)
    {
        if(L == R)
            return a[u];
        int mid = L + R >> 1;
        if(pos <= mid)
            return std::max(a[u], query(u << 1, L, mid, pos));
        else
            return std::max(a[u], query(u << 1 | 1, mid + 1, R, pos));
    }

    inline int query(int pos)
    {
        return query(1, 1, LEN, pos);
    }
}sgt;

struct suffixAutomaton
{
    struct state
    {
        state *suc[26], *pre;
        std::vector<state*> sucOnTr;
        int len, sz, tg;

        inline state()
        {
            for(int i = 0; i < 26; ++ i)
                suc[i] = NULL;
            sucOnTr.clear();
            sz = tg = 0;
        }
    };

    state *rt, *lst;

    inline void insert(int c)
    {
        state *u = new state;
        u->len = lst->len + 1;
        u->sz = 1;
        for(; lst != NULL && lst->suc[c] == NULL; lst->suc[c] = u, lst = lst->pre);
        if(lst == NULL)
            u->pre = rt;
        else
        {
            state *p = lst->suc[c];
            if(p->len == lst->len + 1)
                u->pre = p;
            else
            {
                state *q = new state;
                *q = *p;
                q->sz = 0;
                q->len = lst->len + 1;
                p->pre = u->pre = q;
                for(; lst != NULL && lst->suc[c] == p; lst->suc[c] = q, lst = lst->pre);
            }
        }
        lst = u;
    }

    inline void build(char *str, int len)
    {
        lst = rt = new state;
        rt->len = 0, rt->pre = NULL;
        for(int i = 0; i < len; ++ i)
            insert(str[i] - 'a');
    }

    void getSucessorOnSuffixTree(state *u)
    {
        u->tg = 1;
        if(u->pre != NULL)
            u->pre->sucOnTr.push_back(u);
        for(int i = 0; i < 26; ++ i)
            if(u->suc[i] != NULL && ! u->suc[i]->tg)
                getSucessorOnSuffixTree(u->suc[i]);
    }

    void DFS(state *u)
    {
        for(std::vector<state*>::iterator p = u->sucOnTr.begin(); p != u->sucOnTr.end(); ++ p)
            DFS(*p), u->sz += (*p)->sz;
        if(u != rt)
            sgt.modify(u->pre->len + 1, u->len, u->sz);
    }

    inline void work()
    {
        getSucessorOnSuffixTree(rt);
        DFS(rt);
    }
}SAM;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("SPOJ8222.in", "r", stdin);
    #endif
    static char str[LEN];
    scanf("%s", str);
    int len = strlen(str);
    SAM.build(str, len);
    SAM.work();
    for(int i = 1; i <= len; ++ i)
        printf("%d\n", sgt.query(i));
}

转载于:https://www.cnblogs.com/ZeonfaiHo/p/7126672.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值