动态维护任意两个后缀的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();
}
}