https://ac.nowcoder.com/acm/problem/17633
题意就不说了,那上面说得很清楚了;
这道题最暴力的办法就是,每个字符串都跑next数组,然后kmp匹配,数据很小的时候,可以这样,但不过这道题就不能了,太暴力了。
所以我们还是想想Trie(AC自动机吧),这道题用到了一个很有用的结论,我觉得这个结论在字符串配中还是很重要的
T串为S串的子串,当且仅当T是S的某一个前缀的后缀,这样的前缀的数目的多少,就是T在S中出现的次数。
而fail的指针跳的就是一个前缀的最长匹配后缀
我们这样做,从y字符串方向走fail,有多少个x的结束点就出现了多少次,直接在自动机上条跳fail绝对超时,不管你用什么优化,(dalao除外。。),首先建一颗fail树,有的人可能不会建fail树,其实也不难,就是fail指向跳到他的点,其实就是把fail指针反向。然后把y上的所有结点变成1,然后求fail的树中x的结点的子树中有多个数1,这个东西就可以用dfs序,加上树状数组维护了,这种方法在AC自动机的字符串题目中比较常见。对于一个P操作,就是打印一个串,我们直接把串的最后一个字符的记录下来,用一个pos数组表示字符串的编号,p数组表示,他在Trie上的位置,B操作就是返回他的父亲结点。
在求解答案的时候,当加入一个点时,就对in全部加1,然后查找与他的有关的x串,这个的ans就是ou[x的位置]-in[x的位置-1];这样遍历Trie就可以了。
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int tree[N];
int lowbits(int x){return x&(-x);}
void add(int x,int val)
{
for(;x<N;x+=lowbits(x)) tree[x]+=val;
}
int query(int x)
{
int ret=0;
for(;x;x-=lowbits(x)) ret+=tree[x];
return ret;
}
char str[N];
int fa[N],pos[N],p[N],num;
vector<int>son[N];
int nxt[N][26],fail[N];
int tot=0;
void Insert(char *s)
{
int len=strlen(s),now=0;
num=0;
for(int i=0;i<len;i++)
{
int x=s[i]-'a';
if(s[i]>='a'&&s[i]<='z')
{
if(!nxt[now][x]) nxt[now][x]=++tot,fa[nxt[now][x]]=now;
now=nxt[now][x];
}
else if(s[i]=='P')
pos[now]=++num,p[num]=now;
else
now=fa[now];
}
}
void build()
{
queue<int>qu;
for(int i=0;i<26;i++)
if(nxt[0][i]) qu.push(nxt[0][i]);
while(!qu.empty())
{
int u=qu.front();qu.pop();
for(int i=0;i<26;i++)
{
if(nxt[u][i]!=0) fail[nxt[u][i]]=nxt[fail[u]][i],qu.push(nxt[u][i]);
else nxt[u][i]=nxt[fail[u]][i];
}
}
}
int in[N],ou[N],dfn=0;
vector<int>vec[N];
void dfs(int u,int fa)
{
in[u]=++dfn;
for(int i=0;i<vec[u].size();i++)
{
int v=vec[u][i];
if(v==fa) continue;
dfs(v,u);
}
ou[u]=dfn;
}
vector<pair<int,int> >pa[N];
int x[N],y[N],m,ans[N];
void solve(int u)
{
add(in[u],1);
for(int i=0;i<pa[pos[u]].size();i++)
{
int x=pa[pos[u]][i].first,id=pa[pos[u]][i].second;
ans[id]=query(ou[p[x]])-query(in[p[x]]-1);
}
for(int i=0;i<son[u].size();i++)
{
int v=son[u][i];
solve(v);
}
add(in[u],-1);
}
int main()
{
memset(tree,0,sizeof(tree));
memset(fail,0,sizeof(fail));
memset(nxt,0,sizeof(nxt));
scanf("%s",str);
Insert(str);
for(int i=0;i<=tot;i++)
for(int j=0;j<26;j++)
if(nxt[i][j]) son[i].push_back(nxt[i][j]);
build();
for(int i=1;i<=tot;i++)
{
vec[fail[i]].push_back(i);
//vec[i].push_back(fail[i]);
}
dfs(0,0);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
pa[y[i]].push_back(make_pair(x[i],i));
}
solve(0);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}