题目
分析
这么多串弄个AC自动机吧。。可以在O(n)的时间复杂度弄出那个trie来的
然后如果暴力匹配每个y会超时
有一种叫做fail树的东西,就是把fail指针作为边弄成一棵树,根还是没变,这样的话每个结点所代表的字符串(rt->该结点)是它所有子树所代表的字符串的后缀。
对于一个询问(x,y),x可以对它的子树产生影响,只需要统计它的子树中有多少个结点是rt->y即那次询问的答案。
如何统计答案呢?我们去DFS建立的trie树,然后保持DFS序中为1的元素是根节点到当前结点这条链中的元素,然后对于一个y,我们DFS序中所有有值的元素都是y结点的祖先结点,只需要查询x代表的子树中有多少个元素为1即可(这一段在DFS序中是连续的)。
注意DFS序是fail树的DFS序。DFS的是trie树。DFS序用树状数组维护即可,DFS的时候单点修改,计算答案的时候区间查询。
网上很多用链表的,我用了另外的方法就是直接对y排序然后并不是真正的DFS而是按照我们建立trie的顺序DFS,就可以按照顺序查询而不需要链表了,最终效果其实和DFS是一样的,只是不会返回根节点,但是返回途中根本就没有询问嘛。
(实际上我根本不会链表)
代码
说得比较轻巧,其实是需要码的。
但是不是很难,自从我刷BZOJa+b以后以来第一次1A哎。
#include<queue>
#include<cmath>
#include<cctype>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+105;
int n,m;
char s[maxn];
int l[maxn],r[maxn];
int ans[maxn],belong[maxn];//belong是第i个字符串对应的结点;
struct BIT
{
int N,c[maxn+105];
void Initial()
{
N=n+5;
memset(c,0,sizeof(c));
}
int lowbit(int x)
{
return x&-x;
}
void add(int x,int v)
{
for(;x<=N;x+=lowbit(x))c[x]+=v;
}
int sum(int x)
{
int ret=0;
for(;x;x-=lowbit(x))ret+=c[x];
return ret;
}
int query(int l,int r)
{
return sum(r)-sum(l-1);
}
}bit;
namespace fail_tree
{
int dfn,np,first[maxn];
struct edge{
int to,next;
}E[maxn];
void add(int u,int v)
{
E[++np]=(edge){v,first[u]};
first[u]=np;
}
void DFS(int i)
{
l[i]=++dfn;
for(int p=first[i];p;p=E[p].next)DFS(E[p].to);
r[i]=dfn;
}
}
struct data{
int x,y,id;
friend bool operator<(data a,data b)
{
return a.y<b.y;
}
}q[maxn];
struct AC_zidongji
{
int sub,rt,np,ask,ch[maxn][30],fail[maxn],fa[maxn];
void Initial()
{
sub=1;
rt=np=ask=0;
memset(ch,0,sizeof(ch));
}
int getId(char c)
{
return c-'a';
}
void ins()
{
for(int i=0,now=rt;s[i];i++)
{
if(s[i]=='P')
{
belong[++ask]=now;
}
else if(s[i]=='B')
{
now=fa[now];
}
else
{
int id=getId(s[i]);
now=ch[now][id]?ch[now][id]:(fa[++np]=now,ch[now][id]=np);
}
}
}
void getFail()
{
queue<int>q;
fail[rt]=0;
for(int p=0;p<26;p++)
{
int j=ch[rt][p];
if(j){fail[j]=0,fail_tree::add(fail[j],j),q.push(j);};
}
while(!q.empty())
{
int i=q.front();q.pop();
for(int p=0;p<26;p++)
{
int j=ch[i][p];
if(!j)continue;
q.push(j);
int v;
for(v=fail[i];v && !ch[v][p];v=fail[v]);
fail[j]=ch[v][p];
fail_tree::add(fail[j],j);
}
}
}
void DFS()
{
for(int i=0,now=rt;s[i];i++)
{
if(s[i]=='B')
{
bit.add(l[now],-1);
now=fa[now];
}
else if(s[i]!='P')
{
now=ch[now][getId(s[i])];
bit.add(l[now],1);
}
while(sub<=m && belong[q[sub].y]==now)
{
ans[q[sub].id]=bit.query(l[belong[q[sub].x]],r[belong[q[sub].x]]);
sub++;
}
}
}
void DFS(int i)
{
bit.add(l[i],1);
while(sub<=m && belong[q[sub].y]==i)
{
ans[q[sub].id]=bit.query(l[q[sub].x],r[q[sub].x]);
sub++;
}
for(int p=0;p<26;p++)
{
int j=ch[i][p];
if(!j)continue;
}
bit.add(l[i],-1);
}
}AC;
void Init()
{
scanf("%s",s);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].x,&q[i].y);
q[i].id=i;
}
sort(q+1,q+m+1);
n=strlen(s);
bit.Initial();
AC.Initial();
AC.ins();
AC.getFail();
fail_tree::DFS(0);
}
void solve()
{
AC.DFS();
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}
int main()
{
//freopen("in.txt","r",stdin);
Init();
solve();
return 0;
}