您的位置:首页 > 其它

BZOJ2434 [Noi2011]阿狸的打字机

2016-03-17 17:49 344 查看
  AC自动机+树状数组

  先建出fail树,对于查询x在y中出现几次,就等于在x为根的子树下有多少个节点为单词y在tire树路径上所在的节点,可用dfs+树状数组离线求出答案。

#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<vector>
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
#define N 1000010
using namespace std;
char s
;
int tmp,len,i,fa
,cnt,p
,tot,fail
,c,a,b,ans
;
int C
;
int f
[27],ss,L
,R
,m;
int dp,pre
,tt
,query
;
queue<int> q;
vector<pair<int,int> > vec
;
int lowbit(int x)
{
return x&(-x);
}
void cc(int x,int w)
{
while (x<=ss)
{
C[x]+=w;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans=0;
while (x>0)
{
ans+=C[x];
x-=lowbit(x);
}
return ans;
}
void link(int x,int y)
{
dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;
}
void dfs(int x)
{
int i=p[x];
ss++;L[x]=ss;
while (i)
{
dfs(tt[i]);
i=pre[i];
}
R[x]=ss;
}
void solve()
{
int i,tmp=0,cnt=0,j;
for (i=0;i<len;i++)
if (s[i]=='B')
{
cc(L[tmp],-1);
tmp=fa[tmp];
}
else
if (s[i]=='P')
{
cnt++;
for (j=0;j<vec[cnt].size();j++)
{
int o=query[vec[cnt][j].fi];
ans[vec[cnt][j].sc]=sum(R[o])-sum(L[o]-1);
}
}
else
{
tmp=f[tmp][s[i]-97];
cc(L[tmp],1);
}
}
int main()
{
scanf("%s",s);
len=strlen(s);
tmp=0;
for (i=0;i<len;i++)
if (s[i]=='B')
tmp=fa[tmp];
else
if (s[i]=='P')
{
cnt++;
query[cnt]=tmp;
}
else
{
if (f[tmp][s[i]-97]==0)
{
f[tmp][s[i]-97]=++tot;
fa[tot]=tmp;
}
tmp=f[tmp][s[i]-97];
}

for (i=0;i<26;i++)
if (f[0][i])
{
fail[f[0][i]]=0;
q.push(f[0][i]);
}
while (!q.empty())
{
c=q.front();q.pop();
for (i=0;i<26;i++)
if (f[c][i]==0)
f[c][i]=f[fail[c]][i];
else
{
fail[f[c][i]]=f[fail[c]][i];
q.push(f[c][i]);
}
}

for (i=1;i<=tot;i++)
link(fail[i],i);
dfs(0);
scanf("%d",&m);
for (i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
vec[b].pb(mp(a,i));
}
solve();
for (i=1;i<=m;i++)
printf("%d\n",ans[i]);
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: