您的位置:首页 > 其它

【NOI2011】bzoj2434 阿狸的打字机

2017-04-20 21:30 357 查看
可以把打字的过程看成trie树的构建。把trie树的AC自动机建出来,问题就是询问一个点到根的路径上,有多少点的fail会指到另一个点上。

因为fail指针是树的结构,可以沿着原操作在trie树上走,维护fail树上单点修改、子树查询的操作。按照dfs序用树状数组维护。

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=200010;
vector<int> qry[maxn],son[maxn];
char s[maxn];
int trans[maxn][30],fail[maxn],fa[maxn],que[maxn],
L[maxn],R[maxn],sum[maxn],qx[maxn],ans[maxn],
pos[maxn],
n,q,tot,num,clo;
void dfs(int u)
{
L[u]=++clo;
vector<int>::iterator it;
for (it=son[u].begin();it!=son[u].end();it++) dfs(*it);
R[u]=clo;
}
int query(int p)
{
int ret=0;
for (;p;p-=p&-p) ret+=sum[p];
return ret;
}
void add(int p,int x)
{
for (;p<=clo;p+=p&-p) sum[p]+=x;
}
int main()
{
//freopen("in","r",stdin);
int p=0,hd=1,tl=0,u,v;
vector<int>::iterator it;
scanf("%s",s+1);
n=strlen(s+1);
for (int i=1;i<=n;i++)
if (s[i]=='P') pos[++num]=p;
else if (s[i]=='B') p=fa[p];
else
{
if (!trans[p][s[i]-'a']) fa[trans[p][s[i]-'a']=++tot]=p;
p=trans[p][s[i]-'a'];
}
for (int i=0;i<26;i++)
if (trans[0][i]) que[++tl]=trans[0][i];
while (hd<=tl)
{
u=que[hd++];
for (int i=0;i<26;i++)
if (trans[u][i])
{
que[++tl]=trans[u][i];
fail[trans[u][i]]=trans[fail[u]][i];
}
else trans[u][i]=trans[fail[u]][i];
}
for (int i=1;i<=tot;i++) son[fail[i]].push_back(i);
scanf("%d",&q);
for (int i=1;i<=q;i++)
{
scanf("%d%d",&u,&v);
qx[i]=pos[u];
qry[pos[v]].push_back(i);
}
dfs(0);
p=0;
for (int i=1;i<=n;i++)
if (s[i]=='P')
for (it=qry[p].begin();it!=qry[p].end();it++) ans[*it]=query(R[qx[*it]])-query(L[qx[*it]]-1);
else if (s[i]=='B')
{
add(L[p],-1);
p=fa[p];
}
else
{
p=trans[p][s[i]-'a'];
add(L[p],1);
}
for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息