struct SuffixAutomaton {
static constexpr int N = 1e6;
struct node {
int len, link, nxt[26];
int siz;
} t[N << 1];
int cntNodes;
SuffixAutomaton() {
cntNodes = 1;
fill(t[0].nxt, t[0].nxt + 26, 1);
t[0].len = -1;
}
int extend(int p, int c) {
if (t[p].nxt[c]) {
int q = t[p].nxt[c];
if (t[q].len == t[p].len + 1) {
return q;
}
int r = ++cntNodes;
t[r].siz = 0;
t[r].len = t[p].len + 1;
t[r].link = t[q].link;
copy(t[q].nxt, t[q].nxt + 26, t[r].nxt);
t[q].link = r;
while (t[p].nxt[c] == q) {
t[p].nxt[c] = r;
p = t[p].link;
}
return r;
}
int cur = ++cntNodes;
t[cur].len = t[p].len + 1;
t[cur].siz = 1;
while (!t[p].nxt[c]) {
t[p].nxt[c] = cur;
p = t[p].link;
}
t[cur].link = extend(p, c);
return cur;
}
int cal(string s){
//计算字符串的本质不同子串数量
int n=s.size();
s=" "+s;
int last=1;
rep(i,1,n){
last=extend(last,s[i]-'a');
}
int cnt=0;
for(int i=2;i<=cntNodes;i++){
cnt+=t[i].len-t[t[i].link].len;
}
return cnt;
}
}SAM;