BZOJ 1396 识别子串
题面
Description
Input
一行,一个由小写字母组成的字符串S,长度不超过10^5
Output
L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.
Sample Input
agoodcookcooksgoodfood
Sample Output
1
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4
题解
后缀自动机跑一遍, 得到的Parent Tree上, 存在每个节点的\(size\)即为它所代表的子串的出现次数.
找到每一个叶子节点, 得到它所代表的最短字符串\(str[L .. R]\), 开两棵线段树, 一棵更新\([L .. R]\)区间中的位置的最短识别子串长度, 另一颗更新\([0, L - 1]\)位置上的最短识别子串.
#include <cstdio>
#include <cstring>
#include <algorithm>
const int LEN = (int)1e5;
struct segmentTree
{
int a[LEN << 2];
inline segmentTree()
{
memset(a, 127, sizeof(a));
}
void modify(int u, int curL, int curR, int L, int R, int w)
{
if(curL >= L && curR <= R)
{
a[u] = std::min(a[u], w);
return;
}
int mid = curL + curR >> 1;
if(L <= mid)
modify(u << 1, curL, mid, L, R, w);
if(R > mid)
modify(u << 1 | 1, mid + 1, curR, L, R, w);
}
void modify(int L, int R, int w)
{
modify(1, 0, LEN - 1, L, R, w);
}
int query(int u, int L, int R, int pos)
{
if(L == R)
return a[u];
int mid = L + R >> 1;
if(pos <= mid)
return std::min(a[u], query(u << 1, L, mid, pos));
else
return std::min(a[u], query(u << 1 | 1, mid + 1, R, pos));
}
inline int query(int pos)
{
return query(1, 0, LEN - 1, pos);
}
}A, B;
struct suffixAutomaton
{
struct state
{
state *suc[26], *pre;
int len, sz, tg;
inline state()
{
sz = 1, tg = 0;
for(int i = 0; i < 26; ++ i)
suc[i] = NULL;
}
};
state *rt, *lst;
inline void insert(int c)
{
state *u = new state;
u->len = lst->len + 1;
for(; lst != NULL && lst->suc[c] == NULL; lst->suc[c] = u, lst = lst->pre);
if(lst == NULL)
u->pre = rt;
else
{
state *p = lst->suc[c];
if(p->len == lst->len + 1)
u->pre = p;
else
{
state *q = new state;
*q = *p;
q->len = lst->len + 1;
p->pre = u->pre = q;
for(; lst != NULL && lst->suc[c] == p; lst->suc[c] = q, lst = lst->pre);
}
}
lst = u;
}
inline void build(char *str, int len)
{
lst = rt = new state;
rt->len = 0, rt->pre = NULL;
for(int i = 0; i < len; ++ i)
insert(str[i] - 'a');
}
void getSize(state *u)
{
u->tg = 1;
if(u->pre != NULL)
++ u->pre->sz;
for(int i = 0; i < 26; ++ i)
if(u->suc[i] != NULL && ! u->suc[i]->tg)
getSize(u->suc[i]);
}
void DFS(state *u)
{
u->tg = 2;
if(u->sz == 1)
{
A.modify(u->len - u->pre->len - 1, u->len - 1, u->pre->len + 1);
if(u->len - u->pre->len - 1 > 0)
B.modify(0, u->len - u->pre->len - 2, u->len - 1);
}
for(int i = 0; i < 26; ++ i)
if(u->suc[i] != NULL && u->suc[i]->tg == 1)
DFS(u->suc[i]);
}
inline void work()
{
getSize(rt);
DFS(rt);
}
}SAM;
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ1396.in", "r", stdin);
#endif
static char str[LEN];
scanf("%s", str);
int len = strlen(str);
SAM.build(str, len);
SAM.work();
for(int i = 0; i < len; ++ i)
{
int resA = A.query(i), resB = B.query(i);
printf("%d\n", std::min(resA, resB - i + 1));
}
}