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
3
1 2
1 3
2 3
Sample Output
1
0
HINT
1<=N<=10^5
Source
#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;
}