您的位置:首页 > 其它

[BZOJ2434][NOI2011]阿狸的打字机

2016-02-08 16:25 330 查看
发现一种新的思路,以前从来没有见过的,即AC自动机的fail树。

这一题我们先考虑暴力,从root往Y的最后一个点走,如果走到了X的末点,ans++,如果通过fail指针走到了X的末点,ans++。

反过来考虑,从X的末点开始,如果当前点在Y串或者通过反向的Fail到了Y串,ans++。

又发把fail反向之后得到的是一棵树,那么也就是要求在X末点的子树里有多少个Y点,转化为DFS序后用树状数组维护即可。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define X first
#define Y second
#define LL long long
#define MP make_pair
#define lowbit(x) (x&(-x))
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
const int MAXN=1e5+10;
char s[MAXN];
int n;
int first[MAXN],e=0,next[MAXN],to[MAXN],sum[MAXN*3],ans[MAXN];
void add(int a,int b)
{
++e;next[e]=first[a];first[a]=e;to[e]=b;
}
void _add(int x,int d)
{
while(x<=2*MAXN)
{
sum[x]+=d;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x>0)
{
res+=sum[x];
x-=lowbit(x);
}
return res;
}
struct ACM{
int son[MAXN][27],fa[MAXN],tot,val[MAXN],f[MAXN],FA[MAXN];
int _first[MAXN],_next[MAXN],_e,_to[MAXN],l[MAXN],r[MAXN],dfs_clock;
ACM(){tot=0;memset(son,0,sizeof(son));memset(fa,0,sizeof(fa));memset(FA,0,sizeof(FA));memset(f,0,sizeof(f));memset(val,0,sizeof(val));dfs_clock=0;}
int idx(char c){return c-'a';}
void insert(char* S)
{
int N=strlen(S),u=0,k=0;
for(int i=0;i<N;i++)
{
if(S[i]>='a'&&S[i]<='z')
{
int x=idx(S[i]);
if(!son[u][x])
{
son[u][x]=++tot;
FA[tot]=u;
u=tot;
}
else
u=son[u][x];
}
else if(S[i]=='P')
val[++k]=u;
else if(S[i]=='B')
u=FA[u];
}
}
void getFail()
{
queue<int> q;
f[0]=0;
for(int i=0;i<26;i++)
{
int u=son[0][i];
if(u)
{
q.push(u);f[u]=0;
}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int i=0;i<26;i++)
{
int u=son[r][i];
if(!u)continue;
q.push(u);
int j=f[r];
while(j&&!son[j][i])j=f[j];
f[u]=son[j][i];
}
}
}
void Add(int a,int b)
{
++_e;_next[_e]=_first[a];_first[a]=_e;_to[_e]=b;fa[b]=a;
}
void buildTree()
{
_e=0;
memset(_first,-1,sizeof(first));
fa[0]=0;
queue<int> q;
for(int i=0;i<26;i++)
{
int u=son[0][i];
if(u)q.push(u);
}
while(!q.empty())
{
int u=q.front();q.pop();
Add(f[u],u);
for(int i=0;i<26;i++)
{
int v=son[u][i];
if(!v)continue;
q.push(v);
}
}
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
}
void DFS(int u)
{
l[u]=++dfs_clock;
for(int i=_first[u];i!=-1;i=_next[i])
{
int v=_to[i];
DFS(v);
}
r[u]=++dfs_clock;
}
void solve()
{
int N=strlen(s),u=0,now,cnt=0;
for(int i=0;i<N;i++)
{
if(s[i]>='a'&&s[i]<='z')
{
now=son[u][idx(s[i])];
_add(l[now],1);
u=now;
//DEBUG("+%d %d\n",u,l[u]);
}
else if(s[i]=='P')
{
++cnt;
if(cnt==8)
cnt=8;
for(int i=first[cnt];i!=-1;i=next[i])
{
int v=to[i];
ans[i]=query(r[val[v]])-query(l[val[v]]-1);
}
}
else
{
_add(l[u],-1);
//DEBUG("-%d %d\n",u,l[u]);
u=FA[u];
}
}
}
}ac;
int main()
{
#ifndef ONLINE_JUDGE
freopen("type.in","r",stdin);
freopen("type.out","w",stdout);
#endif
scanf("%s",s);
memset(first,-1,sizeof(first));
ac.insert(s);
ac.getFail();
ac.buildTree();
ac.DFS(0);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d %d",&x,&y);
add(y,x);
}
ac.solve();
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: