仍然是广义SAM,仍然喜欢先建Trie然后在Trie上BFS建SAM的离线算法(因为感觉在线算法太玄学了
将所有串扔到一个Trie树上然后建SAM,对于SAM的每一个点\(x\)维护\(belong_x\)表示属于哪个串(如果属于多个串就\(-1\)),在\(suffix\ link\)改变的时候修改。
在计算答案之前一定要记得先在\(suffix\ link\)上递推一遍更新\(belong_x\),因为在插入某个字符\(p\)的时候,我们的做法是不断在\(parent\)树上跳,到达某个\(u\)满足\(trans_{u,p} \neq null\)的时候就停止并且更新\(belong_{trans_{u,p}}\),但是对于\(trans_{u,p}\)在\(parent\)树上的祖先没有被更新。例如
2
baa
bba
如果不递推一遍就会输出3 2
,但正确答案显然是2 2
,具体原因是在插入\("bba"\)的\(a\)字符的时候会将\("ba"\)所在的状态设为\(-1\),但是它在\(parent\)树上的祖先即\("a"\)所在的状态没有设为\(-1\)。
最后对于每一个不是\(-1\)的SAM上的点统计一下答案就好。
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<queue>
//This code is written by Itst
using namespace std;
const int MAXN = 2e5 + 3;
int ch[MAXN][26] , dep[MAXN] , ind[MAXN] , col[MAXN];
int N , cnt = 1;
char s[MAXN];
namespace SAM{
int Lst[MAXN] , Sst[MAXN] , fa[MAXN] , trans[MAXN][26];
int cnt = 1 , col[MAXN];
int insert(int p , int l , int x , int c){
int t = ++cnt;
Lst[t] = l;
col[t] = c;
while(p && !trans[p][x]){
trans[p][x] = t;
p = fa[p];
}
if(!p){
fa[t] = Sst[t] = 1;
return t;
}
int q = trans[p][x];
Sst[t] = Lst[p] + 2;
if(Lst[q] == Lst[p] + 1){
fa[t] = q;
col[q] = col[q] != c ? -1 : col[q];
return t;
}
int k = ++cnt;
memcpy(trans[k] , trans[q] , sizeof(trans[k]));
Lst[k] = Lst[p] + 1; Sst[k] = Sst[q];
Sst[q] = Lst[p] + 2;
col[k] = col[q] != c ? -1 : col[q];
fa[k] = fa[q]; fa[q] = fa[t] = k;
while(trans[p][x] == q){
trans[p][x] = k;
p = fa[p];
}
return t;
}
long long sum[MAXN];
int in[MAXN];
void work(){
queue < int > q;
for(int i = 2 ; i <= cnt ; ++i)
++in[fa[i]];
for(int i = 2 ; i <= cnt ; ++i)
if(!in[i])
q.push(i);
while(!q.empty()){
int t = q.front();
q.pop();
if(t == 1)
continue;
if(col[t] != col[fa[t]])
col[fa[t]] = -1;
if(!--in[fa[t]])
q.push(fa[t]);
}
for(int i = 2 ; i <= cnt ; ++i)
if(col[i] != -1)
sum[col[i]] += Lst[i] - Sst[i] + 1;
for(int i = 1 ; i <= N ; ++i)
cout << sum[i] << '\n';
}
}
void insert(int ind){
int cur = 1 , L = strlen(s + 1);
for(int i = 1 ; i <= L ; ++i){
if(!ch[cur][s[i] - 'a']){
ch[cur][s[i] - 'a'] = ++cnt;
col[cnt] = ind;
}
else
col[ch[cur][s[i] - 'a']] = -1;
cur = ch[cur][s[i] - 'a'];
}
}
void build(){
queue < int > q;
q.push(ind[1] = 1);
while(!q.empty()){
int x = q.front();
q.pop();
for(int i = 0 ; i < 26 ; ++i)
if(ch[x][i]){
ind[ch[x][i]] = SAM::insert(ind[x] , dep[ch[x][i]] = dep[x] + 1 , i , col[ch[x][i]]);
q.push(ch[x][i]);
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
scanf("%d" , &N);
for(int i = 1 ; i <= N ; ++i){
scanf("%s" , s + 1);
insert(i);
}
build();
SAM::work();
return 0;
}