2434: [Noi2011]阿狸的打字机 fail树+dfs序+树状数组
来源:互联网 发布:阿里云二级域名注册 编辑:程序博客网 时间:2024/05/21 22:33
一天内做了两道AC自动机两道fail树的题目(好吧本质都一样啊就是fail树的不同应用→ →),感觉对fail树的理解逐渐加深。
对于这道题目,即给你N个字符串,每次给定两个字符串x,y,询问x在y中出现的次数。
一个直接的暴力思路是做M遍KMP,复杂度肯定爆表啦。。也就40分。
我们考虑fail树,如果y中有一个节点i指向了x的尾节点,证明字符串y中以I为结尾的后缀和字符串x中以x的尾节点结尾的前缀相同,而以x的尾节点结尾的前缀正是x串,也就出现了一次。那么知道了这一点,y中如果有ans个节点的fail指针指向x的尾节点,那么答案就是这个ans了。
我们可以构建出这棵fail树,因为每个点的出度为1,如果把边反向,我们就会得到一棵树了。而上文提到的ans就是以x的尾节点为根的子树中y中节点出现的次数,这个画画图就知道了。
于是我再次想到了暴力(我太弱啦QAQ),每次暴力dfs,看起来这样还是可以过70分的数据的。
然后我脑洞就开到了这里。。默默地看了题解。。QAQ
我居然连dfs序都没想到。。。
PoPoQQQ:我们把关于y的询问都存在邻接表里
然后把y所有的节点在DFS序中的位置插入树状数组,然后对于关于y的每个询问在树状数组上查询一遍即可。
感觉好机智啊,直接离线处理。
求出DFS序之后 我们回来考虑这些操作序列
尾添加一个字符->添加的字符所在节点加入树状数组
在结尾删除一个字符->删除的字符所在节点从树状数组删除
打印当前字串-> 处理询问
处理询问
真是一道好题啊,最后1A了赞。
#include<cstdio>#define N 100005#define lowbit(i) (i&(-i))#include<cstring>using namespace std;int len,m,cnt,sum,dfn;int in[N],out[N],tree[N<<1];int head[N],head_[N],next[N],next_[N],list[N],list_[N],pos[N],ans[N],fa[N],p[N],q[N],a[N][26];char s[N];inline int read(){ int a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f;}inline void insert(int x,int y){ next[++sum]=head[x]; head[x]=sum; list[sum]=y;}inline void add(int x,int y,int tot){ next_[tot]=head_[x]; head_[x]=tot; list_[tot]=y;}inline void build_tree(){ cnt=1; int x=1,id=0; for (int i=0;i<26;i++) a[0][i]=1; for (int i=0;i<len;i++) switch(s[i]) { case 'B': x=fa[x]; break; case 'P': pos[++id]=x; break; default: if (!a[x][s[i]-'a']) a[x][s[i]-'a']=++cnt,fa[cnt]=x; x=a[x][s[i]-'a']; break; }}inline void build_fail(){ int t=0,w=1,x; q[1]=1; p[1]=0; while (t<w) { x=q[++t]; for (int i=0;i<26;i++) if (a[x][i]) { int k=p[x]; while (!a[k][i]) k=p[k]; p[a[x][i]]=a[k][i]; q[++w]=a[x][i]; } }}void dfs(int x){ in[x]=++dfn; for (int i=head[x];i;i=next[i]) dfs(list[i]); out[x]=++dfn;}inline void Add(int x,int val){ for (int i=x;i<=dfn;i+=lowbit(i)) tree[i]+=val;}inline int query(int x){ int tmp=0; for (int i=x;i;i-=lowbit(i)) tmp+=tree[i]; return tmp;}inline void solve(){ int x=1,id=0; Add(in[1],1); for (int i=0;i<len;i++) switch(s[i]) { case 'P': for (int j=head_[++id];j;j=next_[j]) { int t=pos[list_[j]]; ans[j]=query(out[t])-query(in[t]-1); } break; case 'B': Add(in[x],-1); x=fa[x]; break; default: x=a[x][s[i]-'a']; Add(in[x],1); break; }} int main(){ scanf("%s",s); len=strlen(s); build_tree(); build_fail(); for (int i=1;i<=cnt;i++) insert(p[i],i); m=read(); for (int i=1;i<=m;i++) { int u=read(),v=read(); add(v,u,i); } dfs(0); solve(); for (int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0;}
0 0
- 2434: [Noi2011]阿狸的打字机 fail树+dfs序+树状数组
- BZOJ 2434: [Noi2011]阿狸的打字机【AC自动机,fail树.dfs序,树状数组
- bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)
- 【BZOJ】【P2434】【Noi2011】【阿狸的打字机】【题解】【fail树+dfs序+树状数组】
- 【bzoj2434】[Noi2011]阿狸的打字机 AC自动机+fail树+dfs序+树状数组
- 【AC自动机-fail树+离线+DFS序+树状数组】BZOJ2434(Noi2011)[阿狸的打字机]题解
- bzoj2434 [Noi2011]阿狸的打字机 ( AC自动机 & fail树 + 树状数组 + dfs序 )
- BZOJ 2434 NOI2011 阿狸的打字机 fail树+树状数组
- [AC自动机 fail树 树状数组] BZOJ 2434 [NOI2011] 阿狸的打字机
- BZOJ 2434: [Noi2011]阿狸的打字机(fail树+树状数组)
- 【BZOJ 2434】[Noi2011]阿狸的打字机 Ac自动机+树状数组+dfs序
- bzoj 2434 (NOI2011)阿狸的打字机 【AC自动机】【树状数组】【DFS序】
- [BZOJ2434]NOI2011阿狸的打字机|AC自动机|fail树|树状数组
- BZOJ2434【NOI2011】阿狸的打字机 <AC自动机+Fail树+树状数组>
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
- bzoj2434 阿狸的打字机NOI2011ac自动机+fail树+树状数组+dfs序详解
- BZOJ2434 [Noi2011]阿狸的打字机【AC自动机+dfs序+树状数组】
- 【bzoj2434】【NOI2011】【阿狸的打字机】【AC自动机+dfs序+树状数组】
- Android开发阅读文档资源
- Android 画三角形shape
- 特殊回文数
- Dubbo spring mvc整合示例
- Java之内省机制
- 2434: [Noi2011]阿狸的打字机 fail树+dfs序+树状数组
- COM 组件设计与应用(四)——简单调用组件
- JQuery,没事玩玩
- HN集训201(5+6)酱油记
- 交换机上的三种端口模式
- J2EE基础概念
- 犀牛书随手记-04
- 毕业十年纪念
- POJ 1003 Hangover 水题一道 练习C++编程