题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434

题解:

我写的是离线做法,不知道有没有在线做法。

转化一波题意,\(x\)在AC自动机上代表的字符串在\(y\)代表的字符串中出现的次数等于\(x\)在fail树的子树内有多少个点是\(y\)点Trie树上的祖先。

然后不难得到做法: 将询问离线按照\(y\)在AC自动机上的id排序(一个正常的构建Trie的方式建出来应该就满足节点的编号是它的Trie树DFS序).

在Trie树上DFS, 同时回答询问, 用树状数组维护即可

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 1e5;
const int S = 26;
struct Edge
{
	int v,nxt;
} e[(N<<1)+3];
struct Query
{
	int x,y,id;
	bool operator <(const Query &arg) const
	{
		return y<arg.y;
	}
} qr[N+3];
int fe[N+3];
int dfn[N+3];
int fa[N+3];
int son[N+3][S+3];
int fail[N+3];
char str[N+3];
int stk[N+3];
int id[N+3];
int que[N+3];
int bit[N+3];
int ord[N+3];
int ans[N+3];
int sz[N+3];
int n,q,siz,m,cnt,en;

void addval(int lrb,int val)
{
	while(lrb<=cnt)
	{
		bit[lrb] += val;
		lrb += (lrb&(-lrb));
	}
}

int querysum(int rb)
{
	int ret = 0;
	while(rb)
	{
		ret += bit[rb];
		rb -= (rb&(-rb));
	}
	return ret;
}

void addedge(int u,int v)
{
	en++; e[en].v = v;
	e[en].nxt = fe[u]; fe[u] = en;
}

void buildTrie()
{
	int u = 0,tp = 0; stk[tp] = 0;
	for(int i=1; i<=n; i++)
	{
		if(str[i]=='B')
		{
			stk[tp] = 0; tp--;
			u = stk[tp];
		}
		else if(str[i]=='P')
		{
			m++; id[m] = u;
		}
		else
		{
			str[i]-=96;
			if(!son[u][str[i]]) {siz++; son[u][str[i]] = siz;}
			u = son[u][str[i]];
			tp++; stk[tp] = u;
		}
	}
}

void buildACA()
{
	int head = 1,tail = 0;
	for(int i=1; i<=S; i++) {if(son[0][i]) {tail++; que[tail] = son[0][i];} fail[son[0][i]] = 0;}
	while(head<=tail)
	{
		int u = que[head]; head++;
		addedge(fail[u],u); addedge(u,fail[u]);
		for(int i=1; i<=S; i++)
		{
			if(son[u][i]) {fail[son[u][i]] = son[fail[u]][i]; tail++; que[tail] = son[u][i];}
			else {son[u][i] = son[fail[u]][i];}
		}
	}
}

void dfs(int u)
{
	cnt++; dfn[u] = cnt;
	sz[u] = 1;
	for(int i=fe[u]; i; i=e[i].nxt)
	{
		if(e[i].v==fa[u]) continue;
		fa[e[i].v] = u;
		dfs(e[i].v);
		sz[u] += sz[e[i].v];
	}
}

int main()
{
	scanf("%s",str+1); n = strlen(str+1);
	scanf("%d",&q);
	buildTrie();
	buildACA();
	for(int i=1; i<=q; i++)
	{
		int x,y; scanf("%d%d",&x,&y);
		qr[i].x = id[x]; qr[i].y = id[y]; qr[i].id = i;
	}
	dfs(0);
	sort(qr+1,qr+q+1);
	int u = 0,tp = 0,j = 0; stk[tp] = 0; addval(dfn[u],0);
	for(int i=1; i<=n; i++)
	{
		if(str[i]=='B')
		{
			addval(dfn[u],-1);
			stk[tp] = 0; tp--;
			u = stk[tp];
		}
		else if(str[i]=='P')
		{
			while(j<q && qr[j+1].y==u)
			{
				j++;
				ans[qr[j].id] = querysum(dfn[qr[j].x]+sz[qr[j].x]-1)-querysum(dfn[qr[j].x]-1);
			}
		}
		else
		{
			u = son[u][str[i]];
			tp++; stk[tp] = u;
			addval(dfn[u],1);
		}
	}
	for(int i=1; i<=q; i++)
	{
		printf("%d\n",ans[i]);
	}
	return 0;
}