fail树+树状数组。。
2434: [Noi2011]阿狸的打字机
Time Limit: 10 Sec
Memory Limit: 256 MB
Submit: 1046
Solved: 594
[ Submit][ Status]
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
[ Submit][ Status]
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
#define ERR ;//puts("=======here========");
#define prt(k) ;//cout<<#k"="<<k<<" "
const int N=100400;
int ch[N][26],fail[N],fa[N];
int Size,root;
int newnode() { memset(ch[Size],-1,sizeof ch[0]); Size++; return Size-1; }
void AC_init() { Size=0; root=newnode(); }
int pos[N];
void insert(char s[])
{
int n=strlen(s),u=root,cur=0; fa[0]=0;
for(int i=0;i<n;i++)
{
if(s[i]=='P') pos[++cur]=u;
else {
if(s[i]=='B') u=fa[u];
else {
int& tmp=ch[u][s[i]-'a']; int t=u;
u=(tmp!=-1)?tmp:tmp=newnode(); fa[u]=t;
}
}
}
}
void AC_build()
{
queue<int> q;
for(int i=0;i<26;i++)
{
int& tmp=ch[root][i];
if(tmp==-1) tmp=root;
else { fail[tmp]=root; q.push(tmp); }
}
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=0;i<26;i++)
{
int& tmp=ch[u][i];
if(tmp==-1) tmp=ch[fail[u]][i];
else { fail[tmp]=ch[fail[u]][i]; q.push(tmp); }
}
}
}
struct TREE {
int tree[N<<2];
TREE() { memset(tree,0,sizeof tree) ; }
inline int lowbit(int x) { return x&-x; }
void add(int p,int x)
{
for(int i=p;i<N;i+=lowbit(i)) tree[i]+=x;
}
int sum(int p)
{
int ret=0;
for(int i=p;i>0;i-=lowbit(i)) ret+=tree[i];
return ret;
}
int sum(int l,int r) { return sum(r)-sum(l-1); }
}T;
int Left[N],Right[N];
int tot;
vector<int> g[N];
void dfs(int u)
{
Left[u]=++tot;
for(int i=0;i<g[u].size();i++) dfs(g[u][i]);
Right[u]=tot;
}
int ans[N];
struct data
{
int x,id;
data() {}
data(int _x,int _id) { x=_x; id=_id; }
};
vector<data> q[N];
int Q;
char s[N];
void solve(char s[])
{
int u=root,y=0;
for(int i=0;s[i];i++)
{
if(s[i]=='P') {
++y;
for(int j=0;j<q[y].size();j++)
{ prt(j);
int x=q[y][j].x;
int id=q[y][j].id;
x=pos[x];
ans[id]=T.sum(Left[x],Right[x]);
}
}
else if(s[i]=='B') {
T.add(Left[u],-1);
u=fa[u];
}
else {
u=ch[u][s[i]-'a']; ERR;
T.add(Left[u],1);
}
}
}
int main()
{
AC_init();
scanf("%s",s); insert(s);
cin>>Q;
for(int i=0;i<N;i++) q[i].clear();
for(int i=1;i<=Q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
q[y].push_back(data(x,i));
// printf("id=%d x=%d y=%d\n",i,x,y);
}
AC_build();
// for(int i=1;i<=3;i++) printf("pos[%d]=%d\n",i,pos[i]);
for(int i=1;i<Size;i++) g[fail[i]].push_back(i);
tot=0;
dfs(root);
// for(int i=0;i<Size;i++) printf("left[%d]=%d right[%d]=%d \n",i,Left[i],i,Right[i]);
solve(s);
for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
}
/**
aPaPBbP
3
1 2
1 3
2 3
*/