[NOI2011] 阿狸的打字机

题目链接

  • AC自动机的fail指针构成了失配树
  • 把询问全部放到树上,离线dfs处理(第一遍dfs在fail树上进行,刻画x的出现;第二遍dfs在trie树上进行,利用系统栈刻画y的每个状态)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
string s;
int t[100005][26],tot,cnt,r[100005],fa[100005],fail[100005],dfn[100005],w[100005],sum,ans[100005];
bool b[100005];
vector<int>a[100005];
vector<int>o[100005];
vector<int>g[100005];
queue<int>q;
struct u1
{
	int id,x,y;
}u[100005];
void build()
{
	int cur=0;
	for(int i=0;i<s.size();i++)
	{
		if(s[i]=='B')
		{
			cur=fa[cur];
		}
		else if(s[i]=='P')
		{
			cnt++;
			r[cnt]=cur;
			b[cur]=true;
		}
		else
		{
			if(t[cur][s[i]-'a']==0)
			{
				tot++;
				t[cur][s[i]-'a']=tot;
				fa[tot]=cur;
				o[cur].push_back(tot);
			}
			cur=t[cur][s[i]-'a'];
		}
	}
	for(int i=0;i<26;i++)
	{
		if(t[0][i]!=0)
		{
			q.push(t[0][i]);
		}
	}
	while(!q.empty())
	{
		int n1=q.front();
		q.pop();
		for(int i=0;i<26;i++)
		{
			if(t[n1][i]!=0)
			{
				fail[t[n1][i]]=t[fail[n1]][i];
				q.push(t[n1][i]);
			}
			else
			{
				t[n1][i]=t[fail[n1]][i];
			}
		}
	}
	for(int i=1;i<=tot;i++)
	{
		a[fail[i]].push_back(i);
	}
}
void dfs1(int n1)
{
	sum++;
	dfn[n1]=sum;
	w[n1]=1;
	for(int i=0;i<a[n1].size();i++)
	{
		dfs1(a[n1][i]);
		w[n1]+=w[a[n1][i]];
	}
}
int c[100005];
int lowbit(int n)
{
	return n&(-n);
}
void add(int n1,int va)
{
	while(n1<=sum)
	{
		c[n1]+=va;
		n1+=lowbit(n1);
	}
}
int ask(int n1)
{
	int s=0;
	while(n1>0)
	{
		s+=c[n1];
		n1-=lowbit(n1);
	}
	return s;
}
void dfs2(int n1)
{
	add(dfn[n1],1);
	for(int i=0;i<g[n1].size();i++)
	{
		int x=u[g[n1][i]].x;
		ans[g[n1][i]]=ask(dfn[x]+w[x]-1)-ask(dfn[x]-1);
	}
	for(int i=0;i<o[n1].size();i++)
	{
		dfs2(o[n1][i]);
	}
	add(dfn[n1],-1);
}
int main()
{
	cin>>s;
	build();
	dfs1(0);
	int m;
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		u[i].id=i;
		u[i].x=r[read1()];
		u[i].y=r[read1()];
		g[u[i].y].push_back(u[i].id);
	}
	dfs2(0);
	for(int i=1;i<=m;i++)
	{
		printf("%d\n",ans[i]);
	}
	return 0;
}
posted @ 2024-02-02 15:18  D06  阅读(10)  评论(0编辑  收藏  举报