Description
Input
一行,一个由小写字母组成的字符串S,长度不超过10^5
Output
L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.Sample Input
agoodcookcooksgoodfoodSample Output
1
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4
能对整个串做出贡献的肯定就是right集合大小为1的点,那么只考虑这些点
mx表示这个点最后一个endpos的位置,l表示最小长度,r表示最大长度
1)对于mx-r+1~mx-l+1的位置的贡献,就是mx-i+1
那么我们知道i是一定的,我们开一棵线段树维护mx+1就好了
2)对于mx-l+1~mx的位置的贡献,就是l,也开一棵线段树维护l就好了
最后对于每个位置输出两棵线段树的最小值就可以了..
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int Maxn = 200010;
int F[Maxn], d[Maxn], ch[Maxn][26], tot, now, G[Maxn];
char s[Maxn]; int len;
int Rsort[Maxn], rk[Maxn], mx[Maxn];
int Min[2][Maxn*2], Max[2][Maxn*2], la[2][Maxn*2];
int _min ( int x, int y ){ return x < y ? x : y; }
int _max ( int x, int y ){ return x > y ? x : y; }
int copy ( int p, int c ){
int x = ++tot, y = ch[p][c];
d[x] = d[p]+1;
for ( int i = 0; i < 26; i ++ ) ch[x][i] = ch[y][i];
F[x] = F[y]; F[y] = x;
while ( ~p && ch[p][c] == y ){ ch[p][c] = x; p = F[p]; }
return x;
}
void add ( int c ){
int p, o;
if ( p = ch[now][c] ){
if ( d[p] != d[now]+1 ) copy ( now, c );
now = ch[now][c];
}
else {
d[o=++tot] = d[now]+1; p = now; now = o; G[o] = 1;
while ( ~p && !ch[p][c] ){ ch[p][c] = o; p = F[p]; }
F[o] = ~p ? ( d[p]+1 == d[ch[p][c]] ? ch[p][c] : copy ( p, c ) ) : 0;
}
}
void bulid_tree ( int now, int L, int R ){
Min[0][now] = Min[1][now] = Max[0][now] = Max[1][now] = 0x7fffffff;
if ( L < R ){
int mid = ( L + R ) >> 1, lc = now*2, rc = now*2+1;
bulid_tree ( lc, L, mid );
bulid_tree ( rc, mid+1, R );
}
}
void push_down ( int fl, int now ){
if ( la[fl][now] ){
int lc = now*2, rc = now*2+1;
Min[fl][lc] = Max[fl][lc] = la[fl][lc] = la[fl][now];
Min[fl][rc] = Max[fl][rc] = la[fl][rc] = la[fl][now];
la[fl][now] = 0;
}
}
void change ( int fl, int now, int L, int R, int l, int r, int k ){
if ( l > r ) return;
if ( k > Max[fl][now] ) return;
if ( L == l && R == r && Min[fl][now] > k ){
Min[fl][now] = Max[fl][now] = la[fl][now] = k;
return;
}
if ( L == R ) return;
push_down ( fl, now );
int mid = ( L + R ) >> 1, lc = now*2, rc = now*2+1;
if ( r <= mid ) change ( fl, lc, L, mid, l, r, k );
else if ( l > mid ) change ( fl, rc, mid+1, R, l, r, k );
else change ( fl, lc, L, mid, l, mid, k ), change ( fl, rc, mid+1, R, mid+1, r, k );
Max[fl][now] = _max ( Max[fl][lc], Max[fl][rc] );
Min[fl][now] = _min ( Min[fl][lc], Min[fl][rc] );
}
int query ( int fl, int now, int L, int R, int x ){
if ( L == R ) return Min[fl][now];
push_down ( fl, now );
int mid = ( L + R ) >> 1, lc = now*2, rc = now*2+1;
if ( x <= mid ) return query ( fl, lc, L, mid, x );
else query ( fl, rc, mid+1, R, x );
}
int main (){
int i, j, k;
scanf ( "%s", s+1 );
len = strlen (s+1);
F[0] = -1; tot = now = 0;
for ( i = 1; i <= len; i ++ ){ add (s[i]-'a'); mx[now] = i; }
for ( i = 1; i <= tot; i ++ ) Rsort[d[i]] ++;
for ( i = 1; i <= len; i ++ ) Rsort[i] += Rsort[i-1];
for ( i = tot; i >= 1; i -- ) rk[Rsort[d[i]]--] = i;
for ( i = tot; i >= 1; i -- ){
mx[F[rk[i]]] = _max ( mx[F[rk[i]]], mx[rk[i]] );
G[F[rk[i]]] += G[rk[i]];
}
bulid_tree ( 1, 1, len );
for ( i = 1; i <= tot; i ++ ){
if ( G[i] != 1 ) continue;
int l = d[F[i]]+1, r = d[i];
change ( 0, 1, 1, len, mx[i]-r+1, mx[i]-l+1, d[i]+1 );
change ( 1, 1, 1, len, mx[i]-l+1, mx[i], l );
}
for ( i = 1; i <= len; i ++ ){
printf ( "%d\n", _min ( query ( 0, 1, 1, len, i ) - i, query ( 1, 1, 1, len, i ) ) );
}
return 0;
}