[BZOJ2434][NOI2011]阿狸的打字机-AC自动机
来源:互联网 发布:网路优化 编辑:程序博客网 时间:2024/05/18 00:27
阿狸的打字机
Description
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和’B’、’P’两个字母。
经阿狸研究发现,这个打字机是这样工作的:
l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
l 按一下印有’B’的按键,打字机凹槽中最后一个字母会消失。
l 按一下印有’P’的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
Input
输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。
第二行包含一个整数m,表示询问个数。
接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。
Output
输出m行,其中第i行包含一个整数,表示第i个询问的答案。
Sample Input
aPaPBbP
aPaPBbP
3
1 2
1 3
2 3
Sample Output
2
1
0
HINT
1<=N<=10^5
1<=M<=10^5
输入总长<=10^5
1WA,原因:输出了打印次数个答案,而不是询问次数个答案,结果要么答案少一部分,要么多一堆迷之0……
还有这种操作……
(╯‵□′)╯︵┻━┻
思路:
首先,仔细观察题面,可以发现这个字符串在每个时间的状态都可以用一个栈表示。
那么:
插入一个字符等于在栈顶节点所在AC自动机上位置后插入一个儿子。
删除一个字符等于栈顶-1
打印所有字符等于将栈顶标记为一个字符串的结尾
然后咱就不需要把每个打印串分别求出并插入了~
然后,参见BZOJ3172,考虑使用fail树。
那么咱先对fail树求一遍dfs序,答案便是每个x节点的dfs区间中有多少个属于y的节点,这里属于y的节点的定义为,y串在AC自动机上的每个节点沿fail树走到根的路径上途径的所有点。
很显然,在dfs序上x节点的子树是一段连续的区间。
那么考虑再次模拟所有操作(其实就是对AC自动机进行dfs),使用一个树状数组维护。
每加入一个字符,就把在它dfs序上起点位置处给树状数组加上1。
每删除一个字符,就把刚才加的1减掉。
每遇到一次打印,那么便处理当前节点作为y时的所有询问:直接在树状数组上,对每个询问的x,查询其dfs序区间中的和为多少。
最后得到的查询结果即为在x子树中属于y节点的数量。
这就是答案了~
#include<iostream>#include<vector>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>using namespace std;const int N=1e5+9;int n,m,t,ans[N],dfn;int bit[N],stk[N],top;char operate[N];int to[N],nxt[N],id[N],beg[N],tot;inline void push(int u,int v,int w){ to[++tot]=v; nxt[tot]=beg[u]; id[tot]=w; beg[u]=tot;}inline int lowbit(int x){ return x&(-x);}inline void add(int x,int v){ while(x<=dfn) { bit[x]+=v; x+=lowbit(x); }}inline int query(int x){ int ret=0; while(x) { ret+=bit[x]; x-=lowbit(x); } return ret;}struct AC_automaton{ int ch[N][28],fail[N],end[N],pool; int q[N],l,r,pos[N],st[N],ed[N]; vector<int> g[N]; inline int insert(int now,char c) { if(!ch[now][c-'a']) ch[now][c-'a']=++pool; return ch[now][c-'a']; } inline void set_end(int now,int id) { end[now]=id; } inline void getfail() { l=0; q[r=1]=0; fail[0]=0; while(l<r) { int u=q[++l]; for(int i=0;i<26;i++) if(ch[u][i]) { q[++r]=ch[u][i]; fail[ch[u][i]]= u==0?0:ch[fail[u]][i]; g[fail[ch[u][i]]].push_back(ch[u][i]); } else ch[u][i]= u==0?0:ch[fail[u]][i]; } } inline void dfs(int u) { pos[u]=++dfn; if(end[u]) st[end[u]]=dfn; for(int i=0,e=g[u].size();i<e;i++) dfs(g[u][i]); if(end[u]) ed[end[u]]=dfn; }}koishi;int main(){ scanf("%s",operate+1); t=strlen(operate+1); stk[top=1]=0; for(int i=1;i<=t;i++) switch(operate[i]) { case 'B': top--; break; case 'P': koishi.set_end(stk[top],++n); break; default: stk[++top]=koishi.insert(stk[top-1],operate[i]); break; } koishi.getfail(); koishi.dfs(0); scanf("%d",&m); for(int i=1,x,y;i<=m;i++) { scanf("%d%d",&x,&y); push(y,x,i); } stk[top=1]=0; for(int i=1;i<=t;i++) switch(operate[i]) { case 'B': add(koishi.pos[stk[top]],-1); stk[top--]=0; break; case 'P': for(int i=beg[koishi.end[stk[top]]];i;i=nxt[i]) ans[id[i]]=query(koishi.ed[to[i]])-query(koishi.st[to[i]]-1); break; default: stk[++top]=koishi.ch[stk[top-1]][operate[i]-'a']; add(koishi.pos[stk[top]],1); break; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0;}
- 【BZOJ2434】【NOI2011】阿狸的打字机 AC自动机
- [BZOJ2434][NOI2011]阿狸的打字机-AC自动机
- [BZOJ2434]NOI2011阿狸的打字机|AC自动机|fail树|树状数组
- BZOJ2434 [Noi2011]阿狸的打字机【AC自动机+dfs序+树状数组】
- 【bzoj2434】[Noi2011]阿狸的打字机 AC自动机+fail树+dfs序+树状数组
- [BZOJ2434][NOI2011]阿狸的打字机(AC自动机+树状数组)
- 【bzoj2434】【NOI2011】【阿狸的打字机】【AC自动机+dfs序+树状数组】
- bzoj2434(NOI2011).阿狸的打字机(AC自动机 && DFS序 && 树状数组)
- [BZOJ2434][NOI2011]阿狸的打字机(AC自动机+树状数组)
- 【AC自动机-fail树+离线+DFS序+树状数组】BZOJ2434(Noi2011)[阿狸的打字机]题解
- BZOJ2434【NOI2011】阿狸的打字机 <AC自动机+Fail树+树状数组>
- bzoj2434 [Noi2011]阿狸的打字机 ( AC自动机 & fail树 + 树状数组 + dfs序 )
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
- 【AC自动机】[NOI2011]阿狸的打字机
- bzoj2434: [Noi2011]阿狸的打字机
- [BZOJ2434][NOI2011]阿狸的打字机
- bzoj2434 阿狸的打字机 noi2011
- bzoj2434: [Noi2011]阿狸的打字机
- STM32L073 使用cube生成ADC多路采样错误解决
- Codeforces 845 A Chess Tourney
- 最长上升子序列
- struts2的入门程序
- MyBatis(2)--MyBatis标准示例(单例)
- [BZOJ2434][NOI2011]阿狸的打字机-AC自动机
- python运维first_chapter
- You Don't Know JS: Types & Grammar 总结
- javascript学习记录(二)-function函数的应用之sort()函数详解
- 从零开始学_JavaScript_系列(55)——Generator函数(3)yield*表达式
- 响应式布局学习
- malloc1
- 从零开始学_JavaScript_系列(56)——Generator函数(4)简写,this与继承
- HDU 6166 Senior Pan [二分+SPFA]