【XTU】2016湘潭邀请赛 I Substring Query【AC自动机+分块】

时间复杂度 O(NN)
空间复杂度 O(26N)

PS:这份代码跑了1800ms,之后我和csy把代码卡到了421ms,具体代码就不贴了,常数优化而已,其实还能优化一些,懒得改了

my   code:

#include <bits/stdc++.h>
using namespace std ;

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 100005 ;
const int MAXQ = 100005 ;
const int SQR1 = 128 ;
const int SQR2 = 256 ;

vector < int > G[MAXN] ;
char s[MAXN] , ss[MAXN] ;
string p[MAXQ] ;
int op[MAXQ] ;
int nxt[MAXN][26] , fail[MAXN] , idx[MAXN] , in[MAXN] , ou[MAXN] , point , root , dfs_clock ;
int c[1000] , val[MAXN] ;
int n , m ;
int Q[MAXN] , l , r ;

int newnode () {
    clr ( nxt[point] , 0 ) ;
    return point ++ ;
}

void init () {
    point = 0 ;
    root = newnode () ;
}

void insert ( string& s , int n , int id ) {
    int u = root ;
    for ( int i = 0 ; i < n ; ++ i ) {
        int x = s[i] - 'a' ;
        if ( !nxt[u][x] ) nxt[u][x] = newnode () ;
        u = nxt[u][x] ;
    }
    idx[id] = u ;
}

void dfs ( int u ) {
    in[u] = ++ dfs_clock ;
    for ( int i = 0 ; i < G[u].size () ; ++ i ) dfs ( G[u][i] ) ;
    ou[u] = dfs_clock ;
}

void build () {
    l = r = 0 ;
    fail[root] = root ;
    for ( int i = 0 ; i < 26 ; ++ i ) {
        if ( !nxt[root][i] ) nxt[root][i] = root ;
        else {
            fail[Q[r ++] = nxt[root][i]] = root ;
            G[root].push_back ( nxt[root][i] ) ;
        }
    }
    while ( l != r ) {
        int u = Q[l ++] ;
        for ( int i = 0 ; i < 26 ; ++ i ) {
            if ( !nxt[u][i] ) nxt[u][i] = nxt[fail[u]][i] ;
            else {
                fail[Q[r ++] = nxt[u][i]] = nxt[fail[u]][i] ;
                G[nxt[fail[u]][i]].push_back ( nxt[u][i] ) ;
            }
        }
    }
    dfs_clock = 0 ;
    dfs ( root ) ;
}

inline void add ( int x , int v ) {
    c[x / SQR2] += v ;
    val[x] += v ;
}

int sum ( int x , int y ) {
    int L = x / SQR2 + 1 ;
    int R = y / SQR2 - 1 ;
    int ans = 0 ;
    if ( R + 1 <= L ) {
        for ( int i = x ; i <= y ; ++ i ) {
            ans += val[i] ;
        }   
    } else {
        for ( int i = L ; i <= R ; ++ i ) {
            ans += c[i] ;
        }
        L *= SQR2 ;
        R *= SQR2 ;
        for ( int i = x ; i < L ; ++ i ) {
            ans += val[i] ;
        }
        for ( int i = R + SQR2 ; i <= y ; ++ i ) {
            ans += val[i] ;
        }
    }
    return ans ;
}

int getpos ( char s[] , int L , int R ) {
    int u = root ;
    for ( int i = L ; i < R ; ++ i ) {
        int x = s[i] - 'a' ;
        u = nxt[u][x] ;
    }
    return u ;
}

void addv ( char s[] , int L , int R , int v , int now ) {
    int u = now ;
    for ( int i = L ; i < R ; ++ i ) {
        int x = s[i] - 'a' ;
        u = nxt[u][x] ;
        add ( in[u] , v ) ;
    }
}

void get_fail ( char p[] , int m ) {
    fail[1] = 0 ;
    for ( int i = 2 , j = 0 ; i <= m ; ++ i ) {
        while ( j && p[i] != p[j + 1] ) j = fail[j] ;
        if ( p[i] == p[j + 1] ) ++ j ;
        fail[i] = j ;
    }
}

int kmp ( char s[] , int n , char p[] , int m ) {
    int ans = 0 ;
    for ( int i = 0 , j = 0 ; i < n ; ++ i ) {
        while ( j && s[i] != p[j + 1] ) j = fail[j] ;
        if ( s[i] == p[j + 1] ) {
            ++ j ;
            if ( j == m ) {
                ++ ans ;
                j = fail[j] ;
            }
        } else j = fail[j] ;
    }
    return ans ;
}

void solve () {
    init () ;
    for ( int i = 0 ; i < m ; ++ i ) {
        scanf ( "%d" , &op[i] ) ;
        cin >> p[i] ;
        if ( op[i] == 0 && p[i].length () <= SQR1 ) insert ( p[i] , p[i].length () , i ) ;
    }
    for ( int i = 0 ; i < point ; ++ i ) {
        G[i].clear () ;
    }
    build () ;
    clr ( c , 0 ) ;
    clr ( val , 0 ) ;
    addv ( s , 0 , n , 1 , root ) ;
    for ( int i = 0 ; i < m ; ++ i ) {
        if ( op[i] ) {
            -- op[i] ;
            int L = max ( 0 , op[i] - SQR1 ) , R = min ( n , op[i] + SQR1 ) ;
            int now = getpos ( s , L , op[i] ) ;
            addv ( s , op[i] , R , -1 , now ) ;
            s[op[i]] = p[i][0] ;
            addv ( s , op[i] , R , 1 , now ) ;
        } else {
            if ( p[i].length () > SQR1 ) {
                int len = 0 ;
                for ( int j = 0 ; j < p[i].length () ; ++ j ) {
                    ss[++ len] = p[i][j] ;
                }
                get_fail ( ss , len ) ;
                printf ( "%d\n" , kmp ( s , n , ss , len ) ) ;
            } else {
                int ans = sum ( in[idx[i]] , ou[idx[i]] ) ;
                printf ( "%d\n" , ans ) ;
            }
        }
    }
}

int main () {
    while ( ~scanf ( "%d%d%s" , &n , &m , s ) ) solve () ;
    return 0 ;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值