bzoj1396: 识别子串

14 篇文章 0 订阅

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

能对整个串做出贡献的肯定就是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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值