#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 20 ;
struct SAM{
int t[N][26] , link[N] , len[N];
int last ,tot ;
SAM() : last(1) , tot(1){}
void insert(int c){
int p = last , np = last = ++tot ; //p是之前的节点 np是现新建的节点
len[np] = len[p] + 1 ; //首先会多一个endpos为n的,其他的不可能和他重复
while( p and !t[p][c] )t[p][c] = np , p = link[p];//link[p]相当于fail指针 向上跳使得s -> s的后缀 在后缀上->一个 就相当于是一个新的子串
if(!p)link[np] = 1 ;//如果跳到根了,说明没有与他相同的子串,所以失配只能跳到根
else{//如果有和他一样的子串
int q = t[p][c] ;
if( len[q] == len[p] + 1)link[np] = q ;//如果说是s+c的等价后继类是s的等价类最长的+1 ,那么他就是等价后继类
else{
int nq = ++tot ;
memcpy( t[nq] , t[q] , sizeof(t[q]));//转移函数不变
len[nq] = len[p] + 1 ; //新加了一个c所以长度+1
link[nq] = link[q] ;//
/*如图
nq
/ \
q np
*/
link[np] = link[q] = nq ;//
while( p and t[p][c] == q )t[p][c] = nq , p = link[p];//更新其他的到他的节点
}
}
}
}
void get_sa(){
int m = 255 ;
for(int i = 1 ; i <= n ;++i)cnt[rnk[i] = s[i]]++; //初始化,给长度为1的赋值
for(int i = 1 ; i <= m ;++i)cnt[i] += cnt[i - 1] ;//前缀和,计算
for(int i = n ; i >= 1 ;--i)sa[cnt[rnk[i]]--] = i ;
for(int w = 1 , t = 0 ; ; m = t , t = 0 , w <<= 1 ){//每次倍增长度
for(int i = n - w + 1 ; i <= n ;++i)tmp[++t] = i;//如果 i + w > 0 就把他平行移到左边
for(int i = 1 ; i <= n ;++i)
if( sa[i] > w )tmp[++t] = sa[i] - w ;//否则直接赋值
// for(int i = 1 ; i <= n ; i++){
// cout << i << " " << tmp[i] << " " << w << endl ;
// }
// cout << endl ;
for(int i = 0 ; i <= m ;++i)cnt[i] = 0 ;//重置计数器
for(int i = 1 ; i <= n ;++i)cnt[rnk[tmp[i]]]++;//对第一关键字进行计数排序
for(int i = 1 ; i <= m ;++i)cnt[i] += cnt[i - 1];//前缀和
for(int i = n ; i >= 1 ;--i)sa[cnt[rnk[tmp[i]]]--]= tmp[i];//计算sa
swap(rnk , tmp) , t = 0 ;//这里应该是节省空间 直接使用把老的rnk赋给tmp , 用老的rnk更新新的rnk
for(int i = 1 ; i <= n ; i++)
rnk[sa[i]] = (tmp[sa[i]] == tmp[sa[i - 1]] and tmp[sa[i] + w] == tmp[sa[i - 1] + w] ) ? t : ++t ;
if( t == n )break ;//如果已经够了就不再排序了
}
}
void getHeight(){
for(int i = 1 , k = 0 ; i <= n ; ++i){
if(k)--k;
while(s[i + k] == s[sa[rnk[i] - 1] + k])k++;//直接暴力扩展
height[rnk[i]] = k ;
}
}