动态维护任意两个后缀的lcp集合的mex,支持在串末尾追加字符。

Solution

考虑在 SAM 上求两个后缀的 LCP 的过程,无非就是找它们在 fail 树上的 LCA,那么 LCP 长度就是这个点的 maxlen

那么在这里,当增量添加的时候,如果一个节点有了儿子,那么它就可能成为一个新的 LCP

于是我们在操作父子关系的时候暴力修改一个 bool 数组即可,答案的维护是均摊 \(O(n)\)

注意需要对输出 \(0\) 的情况做特判,比如这个例子

aaaabbbbab

输出的结果应该是

0 0 0 0 4 4 4 4 4 4

居然又卡空格

#include <bits/stdc++.h>
using namespace std;

const int N = 2000005;

int pin=0;
bool b[N];
vector <int> mem;

void push(int x) {
    b[x]=1;
    while(b[pin]) ++pin;
    mem.push_back(x);
}

void clear() {
    for(int x:mem) b[x]=0;
    mem.clear();
    pin=0;
}

struct Suffix_Automata {
    int maxlen[N], trans[N][26], link[N], Size, Last;
    int t[N], a[N], cnt[N];
    Suffix_Automata() { Size = Last = 1; }
    void clear() {
        for(int i=1;i<=Size;i++) {
            maxlen[i]=link[i]=t[i]=a[i]=cnt[i]=0;
            memset(trans[i],0,sizeof trans[i]);
        }
        Size = Last = 1;
    }
    inline void Extend(int id) {
        int cur = (++ Size), p;
        maxlen[cur] = maxlen[Last] + 1;
        cnt[cur] = 1;
        for (p = Last; p && !trans[p][id]; p = link[p]) trans[p][id] = cur;
        if (!p) link[cur] = 1, push(maxlen[1]);
        else {
            int q = trans[p][id];
            if (maxlen[q] == maxlen[p] + 1) link[cur] = q, push(maxlen[q]);
            else {
                int clone = (++ Size);
                maxlen[clone] = maxlen[p] + 1;
                for(int i=0;i<26;i++) trans[clone][i] = trans[q][i];
                link[clone] = link[q]; push(maxlen[link[q]]);
                for (; p && trans[p][id] == q; p = link[p]) trans[p][id] = clone;
                link[cur] = link[q] = clone; push(maxlen[clone]); push(maxlen[clone]);
            }
        }
        Last = cur;
    }
} sam;
char str[N];
int buc[26],tot;
signed main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        tot=0;memset(buc,0,sizeof buc);
        scanf("%s",str+1);
        sam.clear();
        int len=strlen(str+1);
        for(int i=1;i<=len;i++) {
            if(buc[str[i]-'a']==0) ++tot;
            buc[str[i]-'a']++;
            sam.Extend(str[i]-'a');
            printf("%d%s",(tot>1)*pin,i==len?"":" ");
        }
        puts("");
        clear();
    }
}

相关文章: