Sevenk Love Oimaster(trie,MAP后缀自动机)

题意:给出n个串,再m个询问,每次询问一个串s,问给出的n个串中,子串包含s的有几个

解法:给这n个串建立trie,再将trie建成sam,然后我们要知道的是,对于每一个状态u所表示的子串,被几个串包含,这里跟http://blog.csdn.net/no__stop/article/details/38611209这题的处理方法类似,不再赘述。然后询问的串,就去sam上匹配,匹配到哪个节点,就将该节点被几个串包含输出即可。这题字符集有128,建立sam的时候,如果把无用的边也枚举一遍,复杂度过高O(128*2*len),所以用一个map把有用的边存起来就好了,复杂度为O(nlog(字符集))。

代码:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
using namespace std ;

const int maxn = 101111 ;
const int N = maxn << 1;
struct Edge {
    int to , next ;
} edge[N] ;
int head[N] , tot , f[N<<1] ;
void new_edge ( int a , int b ) {
    edge[tot].to = b ;
    edge[tot].next = head[a] ;
    head[a] = tot ++ ;
}

char s[maxn] , s1[maxn] ; int l[maxn] , len ;
int TtoM[maxn<<1] ;
struct LCA {
    int dp[22][N<<1] ;
    int to[N] , tim[N] ;
    int tot , n ;
    int MIN ( int a , int b ) {
        return tim[a] < tim[b] ? a : b ;
    }
    void init () {
        tot = 0 ;
        n = 0 ;
    }
    void dfs ( int u , int fa ) {
        tim[u] = ++ tot ;
        for ( int i = head[u] ; i != -1 ; i = edge[i].next ) {
            int v = edge[i].to ;
            if ( v == fa ) continue ;
            dfs ( v , u ) ;
            dp[0][++n] = u ;
        }
        dp[0][++n] = u ;
        to[u] = n ;
    }
    void rmq () {
        for ( int i = 1 ; i <= 20 ; i ++ ) {
            for ( int j = 1 ; j + (1<<i) - 1 <= n ; j ++ ) {
                dp[i][j] = MIN ( dp[i-1][j] , dp[i-1][j+(1<<i-1)] ) ;
            }
        }
    }
    int query ( int a , int b ) {
        a = to[a] , b = to[b] ;
        if ( a > b ) swap ( a , b ) ;
        int k = b - a + 1 ;
        return MIN ( dp[f[k]][a] , dp[f[k]][b-(1<<f[k])+1] ) ;
    }
} lca ;
namespace SAM  {
    int fa[N] , val[N] ;
    map<int,int> c[N] ;
    int cnt[N] ; int tot , last ;
    int ws[N] , wv[N] ;
    void init () ;
    void solve ( int , int ) ;
    inline int new_node ( int _val ) {
        val[++tot] = _val ;
        c[tot].clear () ;
        cnt[tot] = fa[tot] = 0 ;
        return tot ;
    }
    int ADD ( int k , int p ) {
        int i ;
        int np = new_node ( val[p] + 1 ) ;
        while ( p && !c[p][k] ) c[p][k] = np , p = fa[p] ;
        if ( !p ) fa[np] = 1 ;
        else {
            int q = c[p][k] ;
            if ( val[q] == val[p] + 1 ) fa[np] = q ;
            else {
                int nq = new_node ( val[p] + 1 ) ;
                map<int,int> temp = c[q] ;
                for ( map<int,int>::iterator it = temp.begin() ; it != temp.end () ; ++ it )
                    c[nq][it->first] = it->second ;
                fa[nq] = fa[q] ;
                fa[q] = fa[np] = nq ;
                while ( p && c[p][k] == q ) c[p][k] = nq , p = fa[p] ;
            }
        }
        return np ;
    }
    void SORT () {
        for ( int i = 0 ; i < maxn ; i ++ ) wv[i] = 0 ;
        for ( int i = 1 ; i <= tot ; i ++ ) wv[val[i]] ++ ;
        for ( int i = 1 ; i < maxn ; i ++ ) wv[i] += wv[i-1] ;
        for ( int i = 1 ; i <= tot ; i ++ ) ws[wv[val[i]]--] = i ;
    }
}
namespace Trie {
    int tot ;
    map<int,int> c[maxn] ;
    int new_node () {
        c[tot].clear () ;
        return tot ++ ;
    }
    void init () {
        tot = 0 ;
        new_node () ;
    }
    void insert ( int n ) {
        for ( int i = 1 ; i <= n ; i ++ ) {
            int now = 0 ;
            for ( int j = l[i] ; j < l[i+1] ; j ++ ) {
                int k = s[j] ;
                if ( !c[now][k] ) c[now][k] = new_node () ;
                now = c[now][k] ;
            }
        }
    }
}
queue<int> Q ;
void SAM::init () {
    tot = 0 ;
    TtoM[0] = new_node ( 0 ) ;
    Q.push ( 0 ) ;
#define v Trie::c[u][k]
    while ( !Q.empty () ) {
        int u = Q.front () ; Q.pop () ;
        map<int,int> temp = Trie::c[u] ;
        for ( map<int,int>::iterator it = temp.begin() ; it != temp.end () ; ++ it ) {
            int V = it->second ;
            TtoM[V]=ADD(it->first,TtoM[u]) ;
            Q.push ( V ) ;
        }
    }
}

int cmp ( int a , int b ) {
    return lca.tim[a] < lca.tim[b] ;
}
int sta[maxn] ;
void SAM::solve ( int n , int q ) {
    SORT () ;
    for ( int i = 2 ; i <= tot ; i ++ ) {
        new_edge ( fa[i] , i ) ;
    }
    lca.dfs ( 1 , 0 ) ; lca.rmq () ;
    for ( int i = 1 ; i <= n ; i ++ ) {
        int u = 0 ;
        int top = 0 ;
        for ( int j = l[i] ; j < l[i+1] ; j ++ ) {
            int k = s[j] ;
            u = v ;
            sta[++top] = TtoM[u];
            cnt[TtoM[u]] ++ ;
        }
        sort ( sta + 1 , sta + top + 1 , cmp ) ;
        for ( int j = 2 ; j <= top ; j ++ ) {
            int w = lca.query ( sta[j-1] , sta[j] ) ;
            cnt[w] -- ;
        }
    }
    for ( int i = tot ; i >= 1 ; i -- ) {
        int p = ws[i] ;
        cnt[fa[p]] += cnt[p] ;
    }
   // for ( int i = 1 ; i <= tot ; i ++ )
   //     printf ( "cnt[%d] = %d\n" , i , cnt[i] ) ;
    for ( int i = 1 ; i <= q ; i ++ ) {
        gets ( s1 ) ;
        int len = strlen ( s1 ) ;
        int now = 1 ;
        for ( int j = 0 ; j < len ; j ++ ) {
            int k = s1[j] ;
            if ( !c[now].count(k) ) {
                now = 0 ;
                break ;
            }
            now = c[now][k] ;
        }
      //      printf ( "now = %d\n" , now ) ;
        if ( !now ) puts ( "0" ) ;
        else printf ( "%d\n" , cnt[now] ) ;
    }
}
#undef v

void init () {
    tot = 0 ;
    memset ( head , -1 , sizeof ( head ) ) ;
    lca.init () ;
    Trie::init () ;
}

int main () {
   // freopen ( "a.txt" , "r" , stdin ) ;
   // freopen ( "b.txt" , "w" , stdout ) ;
    f[0] = -1 ;
    for ( int i = 1 ; i < maxn << 2 ; i ++ )
        f[i] = f[i>>1] + 1 ;
    int n , k ;
    scanf ( "%d%d" , &n , &k ) ;
        init () ;
        len = 0 ;
        getchar () ;
        int flag = 0 ;
        for ( int i = 1 ; i <= n ; i ++ ) {
            gets ( s1 ) ;
            int k = strlen ( s1 ) ;
            l[i] = len ;
            for ( int j = 0 ; j < k ; j ++ ) {
                s[len++] = s1[j] ;
            }
        }
        l[n+1] = len ;
        Trie::insert (n) ;
        SAM::init () ;
        SAM::solve ( n , k ) ;
    return 0 ;
}
/*
2 1000
aabab...
---babaa
2 1000
.a
b-
3 3
hi,I'mChuYuXun..YouaresohandsomethatIfallinlovewithyou
butIlovesevenk..you'dbettergoaway
55555555555
ChuYuXun
you
55555555
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值