阿狸的打字机

阿狸的打字机

首先建立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]);
}
posted @ 2020-01-16 20:52  yijan  阅读(104)  评论(0编辑  收藏  举报