BZOJ2434: [Noi2011]阿狸的打字机

来源:互联网 发布:淘宝充值平台入口 编辑:程序博客网 时间:2024/05/16 08:56

Description

 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。

经阿狸研究发现,这个打字机是这样工作的:

l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。

l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。

l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。

例如,阿狸输入aPaPBbP,纸上被打印的字符如下:

a

aa

ab

我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。

阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

Input

 输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

第二行包含一个整数m,表示询问个数。

接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

Output

 输出m行,其中第i行包含一个整数,表示第i个询问的答案。

Sample Input

aPaPBbP

3

1 2

1 3

2 3

Sample Output

2

1

0

HINT

 1<=N<=10^5


1<=M<=10^5

输入总长<=10^5

Source

AC自动机+树状数组
暴力做法是对于每个x,查询有多少个root-y上的点沿着fail一直跳能跳到x
那么我们fail[i]向i连边,构造出一颗树,问题转化为root-y的点有多少个在x的子树中
预处理dfs序的l,r(类似于括号序列),那么可以用树状数组维护了
进入一个点就1-l[x]都+1,退出就-1,查询就是查询l[x]-r[x]的和
将询问离线,对于y挂链表,重新跑一遍即可
#include <bits/stdc++.h>using namespace std;const int MAXN = 100010;int n, m, ans[MAXN], cnt, head[MAXN], l[MAXN], r[MAXN], tim, c[MAXN << 1], pos[MAXN], tot, Head[MAXN];char ch[MAXN];struct edge { int to, nxt; }e[MAXN], q[MAXN];inline void addedge(int x, int y) { e[ ++cnt ].to = y; e[ cnt ].nxt = head[ x ]; head[ x ] = cnt; }inline int lowbit(int x) { return x & -x; }inline void modify(int x, int v) { for( ; x <= tim ; x += lowbit( x ) ) c[ x ] += v; }inline int query(int x) { int ans = 0; for( ; x ; x -= lowbit( x ) ) ans += c[ x ]; return ans; }struct ACAM{int nxt[MAXN][26], fail[MAXN], fa[MAXN];int cnt, now, Q[MAXN];ACAM() { for( int i = 0 ; i < 26 ; i++ ) nxt[ 0 ][ i ] = 1; now = cnt = 1; }inline void build(){scanf( "%s", ch + 1 ); n = strlen( ch + 1 );for( int i = 1 ; i <= n ; i++ ){if( ch[ i ] == 'P' ) { pos[ ++tot ] = now; }else if( ch[ i ] == 'B' ) now = fa[ now ];else{if( !nxt[ now ][ ch[ i ] - 'a' ] ) fa[ nxt[ now ][ ch[ i ] - 'a' ] = ++cnt ] = now;now = nxt[ now ][ ch[ i ] - 'a' ];}}}inline void buildfail(){int ql = 0, qr = 1; Q[ 1 ] = 1;while( ql ^ qr ){int x = Q[ ++ql ];for( int i = 0 ; i < 26 ; i++ )if( nxt[ x ][ i ] ){int k = fail[ x ];while( !nxt[ k ][ i ] ) k = fail[ k ];fail[ nxt[ x ][ i ] ] = nxt[ k ][ i ];Q[ ++qr ] = nxt[ x ][ i ];}}for( int i = 2 ; i <= cnt ; i++ ) addedge( fail[ i ], i );}inline void solve(){now = 1;int tmp = 0;for( int i = 1 ; i <= n ; i++ )if( ch[ i ] == 'B' ) modify( l[ now ], -1 ), now = fa[ now ];else if( ch[ i ] == 'P' ){tmp++;for( int j = Head[ tmp ] ; j ; j = q[ j ].nxt ){int x = pos[ q[ j ].to ];ans[ j ] = query( r[ x ] ) - query( l[ x ] - 1 );}}else now = nxt[ now ][ ch[ i ] - 'a' ], modify( l[ now ], 1 );}}AC;inline void dfs(int x){l[ x ] = ++tim;for( int i = head[ x ] ; i ; i = e[ i ].nxt ) dfs( e[ i ].to );r[ x ] = ++tim;}int main(){AC.build();AC.buildfail();dfs( 1 );scanf( "%d", &m );for( int i = 1 ; i <= m ; i++ ){int x, y;scanf( "%d%d", &x, &y );q[ i ].to = x;q[ i ].nxt = Head[ y ];Head[ y ] = i;}AC.solve();for( int i = 1 ; i <= m ; i++ ) printf( "%d\n", ans[ i ] );return 0;}



0 0
原创粉丝点击