P3065 [USACO12DEC]第一!First!
建立trie树,对于每个字符串的每个字符,容易想到必定小于他的兄弟字符,用拓扑排序判断是否有冲突即可
P4070 [SDOI2016]生成魔咒
求S每个前缀有多少本质不同的子串
可知SAM每次加入一个字符后增加的本质不同的字符串是新增的结点maxlen[np] - minlen[np] + 1 = len[np] - len[fa[np]]

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 1e5 + 10;
int len[maxn << 1],fa[maxn << 1];
unordered_map<int,int> son[maxn << 1];
int size,last;
void Init(){
size = last = 1;
}
int insert(int s){
int p = last,np= ++size; last = np;
len[np] = len[p] + 1;
for(;p && !son[p].count(s);p = fa[p]) son[p][s] = np;
if(!p) fa[np] = 1;
else{
int q = son[p][s];
if(len[p] + 1 == len[q]) fa[np] = q;
else{
int nq = ++size; len[nq] = len[p] + 1;
son[nq] = son[q];
fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for(;son[p].count(s) && son[p][s] == q && p;p = fa[p]) son[p][s] = nq;
}
}
// cout << len[last] << " " << len[fa[last]] << endl;
return len[last] - len[fa[last]];
}
int N;
int main(){
scanf("%d",&N);
LL sum = 0; Init();
for(int i = 1; i <= N ; i ++){
int x; scanf("%d",&x);
sum += insert(x);
printf("%lld\n",sum);
}
return 0;
}
P3346 [ZJOI2015]诸神眷顾的幻想乡
学了一下广义后缀自动机(似乎就是把所有字符串建在同一个SAM上),然后她就是模板题了

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 1e6 + 10;
int len[maxn << 1],fa[maxn << 1];
int son[maxn << 1][10];
int size;
void Init(){
size = 1;
}
int insert(int s,int last){
int p = last,np= ++size;
len[np] = len[p] + 1;
for(;p && !son[p][s];p = fa[p]) son[p][s] = np;
if(!p) fa[np] = 1;
else{
int q = son[p][s];
if(len[p] + 1 == len[q]) fa[np] = q;
else{
int nq = ++size; len[nq] = len[p] + 1;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for(;son[p][s] && son[p][s] == q && p;p = fa[p]) son[p][s] = nq;
}
}
return np;
}
int N,c;
struct Edge{
int to,next;
}edge[maxn * 2];
int head[maxn],tot;
void init(){
for(int i = 0 ; i <= N ; i ++) head[i] = -1;
tot = 0;
}
void add(int u,int v){
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
int a[maxn];
int ind[maxn];
void dfs(int u,int la,int last){
last = insert(a[u],last);
for(int i = head[u]; ~i ; i = edge[i].next){
int v = edge[i].to;
if(v == la) continue;
dfs(v,u,last);
}
}
int main(){
scanf("%d%d",&N,&c);
Init(); init();
for(int i = 1; i <= N ; i ++) scanf("%d",&a[i]);
for(int i = 1; i <= N - 1; i ++){
int u,v; scanf("%d%d",&u,&v);
add(u,v); add(v,u); ind[u]++; ind[v]++;
// cout << u << " " << v << endl;
}
for(int i = 1; i <= N ; i ++){
if(ind[i] == 1){
dfs(i,-1,1);
}
// cout << i << " " << ind[i] << endl;
}
LL ans = 0;
for(int i = 1; i <= size; i ++) ans += len[i] - len[fa[i]];
printf("%lld\n",ans);
return 0;
}
