码迷,mamicode.com
首页 > 其他好文 > 详细

阿狸的打字机

时间:2020-01-16 21:49:40      阅读:68      评论:0      收藏:0      [点我收藏+]

标签:com   cin   www   can   build   name   oid   int   back   

阿狸的打字机

首先建立fail树,考虑离线询问。考虑怎么用ACAM处理一个串在另一个串的出现次数,

可以给询问按照主串分类,对于每一个主串分别处理所有询问。某一个串在主串中出现,主串中位于这个串最后的那个位置跳fail必然可以跳到这个串。所以可以树上差分搞一下

大概没啥问题?


然后写了一发,就70了。

注意到对于100%的数据,没有总长度的限制啊!

但是由于有 $ n $ 的限制,trie中的总点数是很小的。

处理方法类似 CF1207G

  • 在将串加入trie的时候,可以记录一个now表示到现在为止加入的串对应在trie上的节点。如果现在要退格,这个点就向上跳,否则在print的时候就往下插入就好了。这样不难发现插入的时候复杂度是线性的。
  • 在处理询问的时候,可以把询问挂在trie上,然后dfs一遍trie处理所有询问。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include<assert.h>
using namespace std;
#define MAXN 1000006
#define mod 1000000007
int n , m;
int len;
char ch[MAXN] , zh[MAXN]; int en;
int son[MAXN][26] , fa[MAXN] , fail[MAXN] , num[MAXN] , idx , to[MAXN];
int cid = 0;

int head1[MAXN] , tt1[MAXN << 1] , nex1[MAXN << 1] , ecn1;
void ade1( int u , int v ) { 
//  cout << u <<  ' ' << v << endl;
    tt1[++ ecn1] = v , nex1[ecn1] = head1[u] , head1[u] = ecn1;
}

int now = 0 , tim = 0;
void ins( char* ch , int id ) {
//  cout << ch << endl;
    for( int i = 0 ; i < len ; ++ i ) {
//      printf("%d\n",++tim);
        if( !son[now][ch[i] - 'a'] ) son[now][ch[i] - 'a'] = ++ idx , fa[idx] = now , ade1( now , idx );
        now = son[now][ch[i] - 'a'];
    }
    ++ num[now] , to[id] = now;
}

int head[MAXN] , tt[MAXN << 1] , nex[MAXN << 1] , ecn;
void ade( int u , int v ) { 
//  cout << u <<  ' ' << v << endl;
    tt[++ ecn] = v , nex[ecn] = head[u] , head[u] = ecn;
}

void build( ) {
    queue<int> Q;
    for( int i = 0 ; i < 26 ; ++ i ) if( son[0][i] ) Q.push( son[0][i] );
    while( !Q.empty() ) {
        int cur = Q.front( ); Q.pop( );
        ade( fail[cur] , cur );
        for( int i = 0 ; i < 26 ; ++ i ) 
            if( son[cur][i] )
                fail[son[cur][i]] = son[fail[cur]][i] , Q.push( son[cur][i] );
            else 
                son[cur][i] = son[fail[cur]][i];
    }
}
struct que { 
    int t , s , id;
} Q[MAXN] ;
bool cmp( que a , que b ) {
    return a.s < b.s;
}
int dfn[MAXN] , R[MAXN] , clo;
void dfs( int u , int fa ) {
    dfn[u] = ++ clo;
    for( int i = head[u] ; i ; i = nex[i] ) {
        int v = tt[i];
        dfs( v , u );
    }
    R[u] = clo;
}

namespace fwk {
    int T[MAXN];
    void add( int u , int c ) {
        assert( u );
        while( u < MAXN ) T[u] += c , u += ( u & -u );
    }
    int sum( int u ) {
        int ret = 0;
        while( u > 0 ) ret += T[u] , u -= ( u & -u );
        return ret;
    }
}
vector<pair<int,int> > ques[MAXN];
int ans[MAXN];
void dfs1( int u ) {
    fwk::add( dfn[u] , 1 );
    for( int i = 0 ; i < ques[u].size() ; ++ i ) 
        ans[ques[u][i].second] = fwk::sum( R[ques[u][i].first] ) - fwk::sum( dfn[ques[u][i].first] - 1 );
    for( int i = head1[u] ; i ; i = nex1[i] ) {
        int v = tt1[i];
        dfs1( v );
    }
    fwk::add( dfn[u] , -1 );
}

int main( ) {
//  freopen("2.in","r",stdin);
    scanf("%s",ch); n = strlen( ch );
    for( int i = 0 ; i < n ; ++ i ) {
        if( ch[i] == 'P' ) ins( zh , ++ cid ) , len = 0;
        else if( ch[i] == 'B' ) {
            if( len ) -- len;
            else now = fa[now];
        }
        else zh[len ++] = ch[i];
    }
    build( );
    dfs( 0 , 0 );
    cin >> m;
    for( int i = 1 , t , s ; i <= m ; ++ i ) 
        scanf("%d%d",&t ,&s ) , ques[to[s]].push_back( make_pair( to[t] , i ) );
    dfs1( 0 );
//  sort( Q + 1 , Q + 1 + m , cmp );
    for( int i = 1 ; i <= m ; ++ i ) printf("%d\n",ans[i]);
}

阿狸的打字机

标签:com   cin   www   can   build   name   oid   int   back   

原文地址:https://www.cnblogs.com/yijan/p/12203215.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!