【刷题】BZOJ 2434 [Noi2011]阿狸的打字机

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

Solution

AC自动机
不知道性质完全做不了

如果AC自动机中的两个串 \(p\)\(s\) ,满足 \(p\)\(s\) 中出现了 \(k\) 次,那么 \(k\) 等于 \(p\) 串结束点在fail树上的子树中有多少个节点属于串 \(s\)

维护树中一个节点的子树和,就随便搞了,我用的BIT
然后就可以离线了
首先把串按照题目含义建出AC自动机
然后getfail
对询问排序
开始算答案,重新跟着给的串走一遍,达到一个点,把它的贡献加入BIT,离开一个点则减去,那么BIT中保存的就一定是当前达到的点到根路径上的点的贡献
(注意,加贡献一定是加在这个点在fail树中的位置,而不是AC自动机上的位置)
所以如果当前到达了一个询问,就可以直接在BIT查答案了

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10,MAXM=100000+10;
int ch[MAXN][30],fail[MAXN],n,m,cnt,st[MAXN],e,beg[MAXN],nex[MAXN<<1],to[MAXN<<1],nt,ans[MAXN],ed[MAXN],fa[MAXN],fl[MAXN],ps[MAXN];
char s[MAXN];
std::queue<int> q;
struct node{
	int x,y,id;
	inline bool operator < (const node &A) const {
		return y<A.y;
	};
};
node qs[MAXM];
struct BIT{
	int C[MAXN];
	inline int lowbit(int x)
	{
		return x&(-x);
	}
	inline void add(int x,int k)
	{
		while(x<=nt)C[x]+=k,x+=lowbit(x);
	}
	inline int sum(int x)
	{
		int res=0;
		while(x>0)res+=C[x],x-=lowbit(x);
		return res;
	}
};
BIT T;
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y)
{
	to[++e]=y;
	nex[e]=beg[x];
	beg[x]=e;
}
inline void init()
{
	int x=0;
	for(register int i=0,lt=strlen(s);i<lt;++i)
		if(s[i]=='P')fl[x]=++n,ps[n]=x;
		else if(s[i]=='B')x=fa[x];
		else if(!ch[x][s[i]-'a'+1])fa[cnt+1]=x,x=ch[x][s[i]-'a'+1]=++cnt;
		else x=ch[x][s[i]-'a'+1];
}
inline void getfail()
{
	for(register int i=1;i<=26;++i)
		if(ch[0][i])q.push(ch[0][i]);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		for(register int i=1,y,z;i<=26;++i)
			if(ch[x][i])
			{
				y=ch[x][i],z=fail[x];
				while(z&&!ch[z][i])z=fail[z];
				fail[y]=ch[z][i];
				q.push(y);
			}
	}
}
inline void dfs(int x,int f)
{
	st[x]=++nt;
	for(register int i=beg[x];i;i=nex[i])
		if(to[i]==f)continue;
		else dfs(to[i],x);
	ed[x]=nt;
}
inline void solve()
{
	int x=0,nq=1;
	for(register int i=0,lt=strlen(s);i<lt;++i)
	{
		if(s[i]=='P')
			while(fl[x]==qs[nq].y)ans[qs[nq].id]=T.sum(ed[ps[qs[nq].x]])-T.sum(st[ps[qs[nq].x]]-1),++nq;
		else if(s[i]=='B')T.add(st[x],-1),x=fa[x];
		else x=ch[x][s[i]-'a'+1],T.add(st[x],1);
	}
}
int main()
{
	scanf("%s",s);
	init();getfail();
	for(register int i=1;i<=cnt;++i)insert(i,fail[i]),insert(fail[i],i);
	read(m);
	for(register int i=1;i<=m;++i)read(qs[i].x),read(qs[i].y),qs[i].id=i;
	dfs(0,-1);
	std::sort(qs+1,qs+m+1);
	solve();
	for(register int i=1;i<=m;++i)write(ans[i],'\n');
	return 0;
}
posted @ 2018-07-12 21:15  HYJ_cnyali  阅读(118)  评论(0编辑  收藏  举报