BZOJ 2434 NOI2011 阿狸的打字机 fail树+树状数组
来源:互联网 发布:毫州康美中药城淘宝店 编辑:程序博客网 时间:2024/09/21 06:32
题目大意:初始字串为空,首先给定一系列操作序列,有三种操作:
1.在结尾加一个字符
2.在结尾删除一个字符
3.打印当前字串
然后多次询问第x个打印的字串在第y个打印的字串中出现了几次
卡了很久……到底还是对AC自动机了解不是很深啊QAQ
fail树不是很难想 至少在用AC自动机切掉3172之后不是很难想……
首先构建AC自动机 注意由于这个字串的特殊构造 我们不必每打印一个字符串再插入Trie树
令now为当前指针 初始为root 考虑三种操作
在结尾添加一个字符->新建一个子节点(若存在在不用新建),进入该子节点
在结尾删除一个字符->返回到父亲节点
打印当前字串->在当前节点标记是第几个字符串
那么查询x在y中出现了几次 就是查询y有多少个节点沿着fail指针能找到x (AC自动机基本操作)
那么我们反向思考 查询y有多少个节点沿着fail指针能找到x 就是查询x沿着反向的fail指针能找到多少个y的节点
fail指针没有环 每个节点只有一个出度 那么反向之后显然是一棵树 x沿着反向的fail指针所能到达的节点就是x所在的子树
于是我们可以沿着反向的fail指针搞出DFS序 x所在的子树就是DFS中对应的区间 我们要查询的是x对应的区间中有多少个y
想高级数据结构的可以洗洗睡了
我们可以这么搞
对于每个y:
我们把关于y的询问都存在邻接表里 然后把y所有的节点在DFS序中的位置插入树状数组,然后对于关于y的每个询问在树状数组上查询一遍即可。
那么问题来了:这不会TLE么?
答案是不会的 因为这题的特殊性 所以树状数组可以达到O(nlogn)
求出DFS序之后 我们回来考虑这些操作序列
在结尾添加一个字符->添加的字符所在节点加入树状数组
在结尾删除一个字符->删除的字符所在节点从树状数组删除
打印当前字串-> 处理询问
然后就搞出来了 1A我也是醉了
#include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 100100using namespace std;struct Trie{Trie *son[26],*fail;vector<Trie*> next;int ed,pos;void* operator new (size_t);}*root=new Trie,mempool[M],*C=mempool;struct abcd{int to,pos,next;}table[M];int head[M],tot;int n,m,ans[M];char s[M];int start[M],end[M],cnt;int c[M];void* Trie :: operator new (size_t){return C++;}void Add(int x,int y,int z){table[++tot].to=y;table[tot].pos=z;table[tot].next=head[x];head[x]=tot;}void Update(int x,int y){for(;x<=cnt;x+=x&-x)c[x]+=y;}int Get_Ans(int x){int re=0;for(;x;x-=x&-x)re+=c[x];return re;}void Build_Tree(){int i;static Trie* stack[M];static int top;stack[++top]=root;for(i=1;s[i];i++){switch(s[i]){case 'B':stack[top--]=0x0;break;case 'P':stack[top]->ed=++n;break;default:if(!stack[top]->son[s[i]-'a'])stack[top]->son[s[i]-'a']=new Trie;stack[++top]=stack[top-1]->son[s[i]-'a'];break;}}static Trie *q[M];static int r,h;for(i=0;i<26;i++)if(root->son[i]){root->son[i]->fail=root;root->next.push_back(q[++r]=root->son[i]);}while(r!=h){Trie *p=q[++h];for(i=0;i<26;i++)if(p->son[i]){Trie *temp=p->fail;while(temp!=root&&!temp->son[i])temp=temp->fail;if(temp->son[i])temp=temp->son[i];p->son[i]->fail=temp;temp->next.push_back(q[++r]=p->son[i]);}}}void DFS(Trie *p){vector<Trie*>::iterator it;p->pos=++cnt;if(p->ed) start[p->ed]=cnt; for(it=p->next.begin();it!=p->next.end();it++)DFS(*it);if(p->ed) end[p->ed]=cnt;}void Solve(){int i,j;static Trie* stack[M];static int top;stack[++top]=root;for(j=1;s[j];j++){switch(s[j]){case 'B':Update(stack[top]->pos,-1);stack[top--]=0x0;break;case 'P':for(i=head[stack[top]->ed];i;i=table[i].next)ans[table[i].pos]=Get_Ans(end[table[i].to])-Get_Ans(start[table[i].to]-1);break;default:stack[++top]=stack[top-1]->son[s[j]-'a'];Update(stack[top]->pos,1);break;}}}int main(){int i,x,y;scanf("%s",s+1);Build_Tree();DFS(root);cin>>m;for(i=1;i<=m;i++){scanf("%d%d",&x,&y);Add(y,x,i);}Solve();for(i=1;i<=m;i++)printf("%d\n",ans[i]);}
- BZOJ 2434 NOI2011 阿狸的打字机 fail树+树状数组
- [AC自动机 fail树 树状数组] BZOJ 2434 [NOI2011] 阿狸的打字机
- BZOJ 2434: [Noi2011]阿狸的打字机(fail树+树状数组)
- BZOJ 2434: [Noi2011]阿狸的打字机【AC自动机,fail树.dfs序,树状数组
- bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)
- 【BZOJ】【P2434】【Noi2011】【阿狸的打字机】【题解】【fail树+dfs序+树状数组】
- BZOJ 2434 [Noi2011] 阿狸的打字机 Fail树
- 2434: [Noi2011]阿狸的打字机 fail树+dfs序+树状数组
- [BZOJ2434]NOI2011阿狸的打字机|AC自动机|fail树|树状数组
- 【bzoj2434】[Noi2011]阿狸的打字机 AC自动机+fail树+dfs序+树状数组
- 【AC自动机-fail树+离线+DFS序+树状数组】BZOJ2434(Noi2011)[阿狸的打字机]题解
- BZOJ2434【NOI2011】阿狸的打字机 <AC自动机+Fail树+树状数组>
- bzoj2434 [Noi2011]阿狸的打字机 ( AC自动机 & fail树 + 树状数组 + dfs序 )
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
- BZOJ 2434([Noi2011]阿狸的打字机-AC自动机-Fail树)
- BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机 fail树
- [BZOJ]2434 阿狸的打字机 AC自动机+Fail树+树状数组
- BZOJ 2434 阿狸的打字机 (AC自动机 fail树 树状数组)
- 博客搬家了
- Android 手机定位慢的解决方法
- 第十四周项目二—带姓名的成绩单
- 第13周上机实践项目5——字符串操作(2)
- tcp通信中的bind
- BZOJ 2434 NOI2011 阿狸的打字机 fail树+树状数组
- lucene应用
- 使用 CAS 在 Tomcat 中实现单点登录
- linux下安装python
- MongoDB命令及SQL语法对比
- libevent学习__学习历程总结
- 社区发现(Community Detection)算法
- 关于VC6简单实现xp风格界面
- jquery实现跨域请求&SpringMVC解决跨域乱码问题