[NOI2011]阿狸的打字机

首先,可以发现这样一个性质
x在y中出现过=======y的某个前缀的后缀等于x。

先把AC自动机建出来后。
y的每一个前缀就是它在trie树上所遍历到的每一个点。
check这个点的后缀是否等于x也就是看沿着fail指针向上能否走到x。
这也就等价于这个点在x的子树中。
考虑去如何加速这个过程。
可以先把属于y的每一个点都先标记一下,对于询问x直接查询子树权值和即可。
综上,把询问按照y排序,在trie树上游走,进入一个点就给这个点+1,退出这个点就给这个点-1。
当走完y以后,处理所有关于y的询问。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<algorithm>
#define N 1100000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline int read()
{
	char ch=0;
	int x=0,flag=1;
	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*flag;
}
queue<int>q;
char ch[N];
int root=1,size=1,s[N],f[N],id[N],nxt[N][27];
struct edge
{
	int to;
	int nxt;
}e[N];
int num,head[N];
inline void add(int x,int y)
{
	e[++num]=(edge){y,head[x]};
	head[x]=num;
}
struct node
{
	int x,y,id;
}p[N];
bool cmp(node a,node b)
{
	return a.y<b.y;
}
int m,times,sz[N],dfn[N],ans[N];
void dfs(int x)
{
	sz[x]=1;dfn[x]=++times;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int to=e[i].to;
		dfs(to);sz[x]+=sz[to];
	}
}
struct Fenwick_Tree
{
	int s[N];
	inline void add(int x,int num)
	{
		for(;x<=size;x+=((x)&(-x)))s[x]+=num;
	}
	inline int query(int x)
	{
		int ans=0;
		for(;x;x-=((x)&(-x)))ans+=s[x];
		return ans;
	}
}T;
void insert()
{
	int n=strlen(ch),x=root,top=0,cnt=0;
	s[0]=root;
	for(int i=0;i<n;i++)
	{
		if('a'<=ch[i]&&ch[i]<='z')
		{
			int k=ch[i]-'a';
			if(!nxt[x][k])nxt[x][k]=++size;
			x=nxt[x][k];s[++top]=x;
		}
		if(ch[i]=='B')
		{
			top--;
			x=s[top];
		}
		if(ch[i]=='P')
		{
			cnt++;
			id[cnt]=x;
		}
	}	
}
void build()
{
	q.push(root);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		for(int i=0;i<26;i++)
		{
			if(nxt[x][i])
			{
				if(x!=root)f[nxt[x][i]]=nxt[f[x]][i];
				else f[nxt[x][i]]=root;
				q.push(nxt[x][i]);
			}
			else
			{
				if(x!=root)nxt[x][i]=nxt[f[x]][i];
				else nxt[x][i]=root;
			}
		}
	}
}
void solve()
{
	int n=strlen(ch),x=root,top=0,cnt=0;
	s[0]=root;
	for(int i=0,j=0;i<n;i++)
	{
		if('a'<=ch[i]&&ch[i]<='z')
		{
			int k=ch[i]-'a';
			x=nxt[x][k];s[++top]=x;
			T.add(dfn[s[top]],+1);
		}
		if(ch[i]=='B')
		{
			T.add(dfn[s[top]],-1);
			top--;x=s[top];
		}
		if(ch[i]=='P')
		{
			cnt++;
			while(j<m&&cnt==p[j+1].y)
			{
				int k=id[p[++j].x];
				ans[p[j].id]=T.query(dfn[k]+sz[k]-1)-T.query(dfn[k]-1);
			}
		}
	}	
}
int main()
{
	scanf("%s",ch);insert();build();
	for(int i=2;i<=size;i++)add(f[i],i);
	dfs(root);
	m=read();
	for(int i=1;i<=m;i++)
	{
		p[i].id=i;
		p[i].x=read();
		p[i].y=read();
	}
	sort(p+1,p+m+1,cmp);
	solve();
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 
	return 0;
}
posted @ 2018-12-06 00:05  Creed-qwq  阅读(205)  评论(0编辑  收藏  举报