zoukankan      html  css  js  c++  java
  • BZOJ 4556 [HEOI2016/TJOI2016]字符串

    BZOJ 4556 [HEOI2016/TJOI2016]字符串

    其实题解更多是用后缀数组+数据结构的做法,貌似也不好写。

    反正才学了 sam 貌似比较简单的做法。

    还是得先二分,然后倍增跳到 $ s[c...c+mid-1] $ 所在的节点,然后看看有没有 endpos 在 $ a+mid-1...b $ 内就好了。

    复杂度是二分和倍增的 $ nlog^2n $。

    其实这道题因为只用求 endpos 是否存在啥的 vector + lower_bound 貌似都可以过了。。但其实启发式合并也不好写,还是写一下线段树合并吧,有些时候会要求维护一些其他的信息,而且复杂度只在最初合并有区别,并不是复杂度瓶颈。

    开始线段树写成 On T了半天海星。。

    #include "iostream"
    #include "algorithm"
    #include "cstring"
    #include "cstdio"
    #include "ctime"
    using namespace std;
    #define MAXN 200006
    int n , m , ps;
    char ch[MAXN];
    namespace solve {
    
        int T[MAXN*20] , ls[MAXN*20] , rs[MAXN*20] , rt[MAXN] , cn;
        void add( int& rt , int l , int r , int p ) {
            if( !rt ) rt = ++ cn;
            ++ T[rt];
            if( l == r ) return;
            int m = l + r >> 1;
            if( p <= m ) add( ls[rt] , l , m , p );
            else add( rs[rt] , m + 1 , r , p );
        }
        int merge( int u , int v , int l , int r ) {
            if( !u || !v ) return u ^ v;
            int cur = ++ cn , m = l + r >> 1;
            T[cur] = T[u] + T[v];
            if( l == r ) return cur;
            ls[cur] = merge( ls[u] , ls[v] , l , m );
            rs[cur] = merge( rs[u] , rs[v] , m + 1 , r );
            return cur;
        }
        int que( int rt , int l , int r , int L , int R ) {
            if( !rt ) return 0;
            if( L <= l && R >= r ) return T[rt];
            int m = l + r >> 1 , res = 0;
            if( L <= m ) res += que( ls[rt] , l , m , L , R );
            if( R > m ) res += que( rs[rt] , m + 1 , r , L , R );
            return res;
        }
    
        int son[MAXN][26] , len[MAXN] , par[MAXN] , lst[MAXN];
        int last , cnt;
    
        int head[MAXN] , to[MAXN] , nex[MAXN] , ecn;
        void ade( int u , int v ) {
            to[++ ecn] = v , nex[ecn] = head[u] , head[u] = ecn;
        }
        void addall( ) {
            for( int i = 2 ; i <= cnt ; ++ i ) ade( par[i] , i );
        }
    
        void init( ) {
            cnt = last = 1;
        }
        void ins( int c ) {
            int cur = ++ cnt;
            len[cur] = len[last] + 1;
            int p = last;
            while( p && !son[p][c] ) son[p][c] = cur , p = par[p];
            if( !p ) par[cur] = 1;
            else {
                int q = son[p][c];
                if( len[q] == len[p] + 1 ) par[cur] = q;
                else {
                    int cl = ++ cnt;
                    memcpy( son[cl] , son[q] , sizeof son[q] );
                    par[cl] = par[q] , len[cl] = len[p] + 1;
                    par[q] = par[cur] = cl;
                    while( p ) { if( son[p][c] == q ) son[p][c] = cl; p = par[p]; }
                }
            }
            last = cur , lst[++ ps] = cur;
            add( rt[cur] , 1 , n , ps );
        }
        int G[MAXN][19];
        int work( int u , int ln ) {
            for( int k = 18 ; k >= 0 ; -- k )
                if( len[G[u][k]] >= ln ) u = G[u][k];
            return u;
        }
        void dfs( int u , int fa ) {
            for( int i = head[u] ; i ; i = nex[i] ) {
                int v = to[i];
                if( v == fa ) continue;
                G[v][0] = u;
                for( int k = 1 ; k < 19 ; ++ k )
                    if( G[G[v][k-1]][k-1] ) G[v][k] = G[G[v][k-1]][k-1];
                    else break;
                dfs( v , u );
                rt[u] = merge( rt[u] , rt[v] , 1 , n );
            }
        }
    }
    
    int main() {
    	//freopen("7.in","r",stdin);
    	//freopen("ot","w",stdout);
        cin >> n >> m;
        scanf("%s",ch + 1);
        using namespace solve;
        init( );
        for( int i = 1 ; i <= n ; ++ i )
            ins( ch[i] - 'a' );
        addall( );
        dfs( 1 , 1 );
        for( int i = 1 , a , b , c , d ; i <= m ; ++ i ) {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            int l = 1 , r = d - c + 1;
            while( l <= r ) {
                int mid = l + r >> 1;
                int t = work( lst[c + mid - 1] , mid );
                if( que( rt[t] , 1 , n , a + mid - 1 , b ) ) l = mid + 1;
                else r = mid - 1;
            }
            printf("%d
    ",r);
        }
    }
    
    
  • 相关阅读:
    Linux安装和配置java
    动态代理:JDK动态代理和CGLIB代理的区别
    常用算法复习
    Linux重新学习
    oracle复杂查询是sql
    oracle触发器
    oracle存储过程
    oracle数据库操作
    java知识回顾
    Spring AOP简述
  • 原文地址:https://www.cnblogs.com/yijan/p/bzoj4556.html
Copyright © 2011-2022 走看看