You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as the maximal number of times that some string with length x appears in S. For example for string 'ababa' F(3) will be 2 because there is a string 'aba' that occurs twice. Your task is to output F(i) for every i so that 1<=i<=|S|.
Input
String S consists of at most 250000 lowercase latin letters.
Output
Output |S| lines. On the i-th line output F(i).
Example
Input: ababa Output: 3 2 2 1 1
题解:SAM模板题。
代码:
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1000005;
typedef struct Node
{
int len, pre;//pre:对应图片中的绿线(一个节点显然最多只有一条绿线)
int Next[26];//Next[]:对应图片中的蓝线
}Node;
Node tre[MAXN*2];
vector<int> G[MAXN*2];//用于建Suffix Links树
int cnt, last, siz[MAXN*2], ans[MAXN*2];
char str[MAXN];
void Insert(char ch)
{
int p, q, now, rev;
p = last, now = cnt++;
tre[now].len = tre[last].len+1;
siz[now]++; //如果节点u包含子串S[1..i],那么满足|siz(u)| = ∑|siz(son(u))|+1,这里先加上那个1,这样的话对于SL树就可以直接求和了
while(p!=-1 && tre[p].Next[ch-'a']==0) //每次跳到当前最长且siz集合与当前不同的后缀上,对应图片中的绿线回退(例如7→8→5→S)
{
tre[p].Next[ch-'a'] = now; //tran(st[p], ch)=now,对应图片中的蓝线连接
p = tre[p].pre;
}
if(p==-1)
tre[now].pre = 0; //情况①,递归到了初始节点S(空子串)(例如图片中的9号节点pre[9]=0)
else //如果中途某个子串tran(st[p], ch)已经存在
{
q = tre[p].Next[ch-'a'];
if(tre[q].len==tre[p].len+1) //情况②:节点q的最长子串刚好就是节点p的最长子串+S[i],也就是len[q] = len[p]+1
tre[now].pre = q;
else //情况③
{
rev = cnt++;
tre[rev] = tre[q];
tre[rev].len = tre[p].len+1; //这三行就是对Suffix Links内向树的插点操作
tre[q].pre = tre[now].pre = rev;
while(p!=-1 && tre[p].Next[ch-'a']==q)
{
tre[p].Next[ch-'a'] = rev;
p = tre[p].pre;
}
}
}
last = now;
}
void SechSL(int u) //求出所有节点的|endpos()|
{
int v;
for(int i=0 ; i<G[u].size() ; ++i)
{
v = G[u][i];
SechSL(v);
siz[u] += siz[v];
}
ans[tre[u].len] = max(ans[tre[u].len], siz[u]);
}
inline void Init()
{
cnt = last = 0;
memset(tre, 0, sizeof(tre));
for(int i=0 ; i<MAXN*2 ; ++i)G[i].clear();
tre[cnt++].pre = -1;
}
int main()
{
int n;
scanf("%s", str+1);
n = strlen(str+1);
Init();
for(int i=1 ; i<=n ; ++i)Insert(str[i]);
for(int i=1 ; i<=cnt-1 ; ++i)G[tre[i].pre].push_back(i);//建树
SechSL(0);
/*---------------------------
LL ans = 0;
for(i=1;i<=cnt-1;i++)
ans += tre[i].len-tre[tre[i].pre].len; //求出有多少个本质不同的子串
-----------------------------*/
for(int i=n ; i>=1 ; i--)
ans[i] = max(ans[i], ans[i+1]);
for(int i=1 ; i<=n ; ++i)
printf("%d\n", ans[i]);
return 0;
}