#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct SAM
{
string s;
int size, last;
vector<int>len, link,siz,t,AN;
vector<vector<int>> to;
//字符串长度,字符集大小
void Init(int strlen, int chSize)
{
size = 1;
last = 1;
len.resize(strlen << 1,0);
AN.resize(strlen << 1,0);
t.resize(strlen << 1,0);
link.resize(strlen << 1,0);
siz.resize(strlen << 1,0);
to.resize(strlen << 1,vector<int>(chSize,0));
}
//清空
void clear()
{
to.clear();
len.clear();
link.clear();
}
//为当前的SAM增加一个字符C
void extend(int c)
{
int p,cur = ++size;
len[cur] = len[last] + 1;
siz[cur] = 1;//表示某个子串出现次数
//情况1
for(p = last; p && !to[p][c]; p = link[p])
{
to[p][c] = cur;
}
if(!p) link[cur] = 1;
else
{
int q = to[p][c];
//情况2 - A
if(len[q] == len[p] + 1) link[cur] = q;
else
{
//情况2 - B
int cl = ++size;
len[cl] = len[p] + 1;
to[cl] = to[q],link[cl] = link[q];
while(p && to[p][c] == q)
{
to[p][c] = cl;
p = link[p];
}
link[cur] = link[q] = cl;
}
}
last = cur;
}
void TOPU()
{
for(int i = 1; i <= size; i ++ ) t[len[i]] ++;
for(int i = 1; i <= size; i ++ ) t[i] += t[i - 1];
for(int i = 1; i <= size; i ++ ) AN[t[len[i]]--] = i;
for(int i = size; i >= 1; i -- ) siz[link[AN[i]]] += siz[AN[i]];
}
int find(string& ok)
{
if(ok.length() > s.length()) return 0;
int now = 1;
for(int i = 0; i < (int)ok.length(); i ++ )
{
if(to[now][ok[i] - 'a' + 1]) now = to[now][ok[i] - 'a' + 1];
else return 0;
}
return 1;
}
void build()
{
cin >> s;
Init(s.length(),30);
ll ans = 0;
for(int i = 0; i < (int)s.length(); i ++ ) extend(s[i] - 'a' + 1);
TOPU();
for(int i = 1; i <= size; i ++ )
{
if(siz[i] > 1)
{
ans = max(ans,1LL * siz[i] * len[i]);
}
}
cout << ans << '\n';
}
}sam;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
sam.build();
return 0;
}
广义SAM
//if(to[last][c])
//{
// int q = to[last][c];
// int p = last;
// if(len[p] + 1 == len[q])
// {
// last = q;
// return;
// }
// int cl = ++size;
// link[cl] = link[q];
// link[q] = cl;
// len[cl] = len[p] + 1;
// to[cl] = to[q];
// while(p && to[p][c] == q)
// {
// to[p][c] = cl;
// p = link[p];
// }
// last = cl;
// return;
//}
Tire树版
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int M = 2e6 + 10;
struct Tire
{
int v[11];
int ch;
int fa;
int ls;
};
struct SAM
{
int idx = 1;
Tire tr[M];
// string s;
int col[M];
int size,last;
vector<int>len, link,pos,dad,deg;
vector<int>e[M];
vector<vector<int>> to;
//字符串长度,字符集大小
void Init(int strlen, int chSize)
{
last = 1;
size = 1;
len.resize(M,0);
link.resize(M,0);
deg.resize(strlen + 1,0);
to.resize(M,vector<int>(chSize + 1,0));
}
//清空
void clear()
{
to.clear();
len.clear();
link.clear();
}
//为当前的SAM增加一个字符C
void extend(int c)
{
int p,cur = ++size;
len[cur] = len[last] + 1;
//情况1
for(p = last; p && !to[p][c]; p = link[p])
{
to[p][c] = cur;
}
if(!p) link[cur] = 1;
else
{
int q = to[p][c];
//情况2 - A
if(len[q] == len[p] + 1) link[cur] = q;
else
{
//情况2 - B
int cl = ++size;
len[cl] = len[p] + 1;
to[cl] = to[q],link[cl] = link[q];
while(p && to[p][c] == q)
{
to[p][c] = cl;
p = link[p];
}
link[cur] = link[q] = cl;
}
}
last = cur;
}
void bfs()
{
queue<int>q;
for(int i = 1; i <= 10; i ++ ) if(tr[1].v[i]) q.push(tr[1].v[i]);
tr[1].ls = 1;
while(q.size())
{
int u = q.front();
q.pop();
last = tr[tr[u].fa].ls;
extend(tr[u].ch);
tr[u].ls = last;
for(int i = 1; i <= 10; i ++ ) if(tr[u].v[i]) q.push(tr[u].v[i]);
}
}
int insert(int p,int c)
{
if(!tr[p].v[c])
{
tr[p].v[c] = ++idx;
tr[idx].fa = p;
tr[idx].ch = c;
}
return tr[p].v[c];
}
void dfs(int u,int dad,int dad_pos)
{
int pos = insert(dad_pos,col[u]);
for(int v : e[u]) if(v != dad) dfs(v,u,pos);
}
void build()
{
int n,c;
cin >> n >> c;
Init(n,c);
for(int i = 1; i <= n; i ++ )
{
cin >> col[i];
col[i] ++;
}
for(int i = 1; i < n; i ++ )
{
int u,v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
deg[u] ++;
deg[v] ++;
}
for(int i = 1; i <= n; i ++ ) if(deg[i] == 1) dfs(i,0,1);//找出所有的串
// 建立Tire树
bfs();
ll ans = 0;
for(int i = 1; i <= size; i ++ ) ans += len[i] - len[link[i]];
cout << ans << '\n';
}
}sam;
int main()
{
sam.build();
return 0;
}