BZOJ2434 [Noi2011]阿狸的打字机【AC自动机+dfs序+树状数组】

来源:互联网 发布:照片幻灯片制作软件 编辑:程序博客网 时间:2024/06/05 07:01

题意:给出阿狸的打字顺序(小写字母是写入,‘B'是删除,’P'是打印,此处产生新的字符串),给出多组询问,每次询问第x号字符串在第y号字符串中的出现次数。

学过AC自动机的都知道,自动机上串A在串B中的出现次数,就是fail树上以串A结尾节点为根的子树中,串B的节点个数。这题我们用离线的方法,以y为关键字排序,在fail树的dfs序上用树状数组维护节点个数。为什么要按y为关键字排序呢?忽略‘P'操作,你没发现它打印删除打印删除的,挺像树的入栈出栈序的么。。。然后按y排序,后面的串上节点个数,就是入栈出栈序的前缀和啊0.0。(怎么觉得描述出来乱乱的,不好意思,词穷词穷= =。)

算法流程:

1.根据输入建立AC自动机,把fail树搞出来。

2.将询问以y为关键字排序。

3.扫一遍输入的串,如果是小写字母,就在树状数组中把该点位置+1,如果是‘B',就把它删除的对应节点在树状数组中-1,如果是’P',在树状数组中截取x的一段区间即是答案。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<bitset>#include<queue>#include<vector>#define ll long long#define N 100010#define INF 0x3f3f3f3fusing namespace std;char str[N];int m;int tr[N][30],g[N],id,pnt[N],len;int end[N],begin[N],in[N],out[N],_index=0;vector<int> e[N];int ans[N],r[N];queue<int> q;struct node{int a,b;int id;node(){}node(int x,int y){a=x;b=y;}friend bool operator < (node x,node y){return x.b==y.b ? x.a<y.a : x.b<y.b;}}que[N];void build(){pnt[1]=0;int x=1;for(int i=0;i<len;i++){if(str[i]=='B'){x=pnt[x];}else if(str[i]=='P'){id++;end[id]=x;}else{if(!tr[x][str[i]-'a']) {tr[x][str[i]-'a']=i+2; pnt[i+2]=x;}x=tr[x][str[i]-'a'];}}}void init(){gets(str);len=strlen(str);build();scanf("%d",&m);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);que[i].a=end[x];que[i].b=end[y];que[i].id=i;}}void bfs(){int j,y;g[1]=0;q.push(1);while(q.size()){int x=q.front();q.pop();for(int i=0;i<26;i++){if(y=tr[x][i]){for(j=g[x];j;j=g[j]) if(tr[j][i]) break;if(j){g[y]=tr[j][i];e[tr[j][i]].push_back(y);}else{g[y]=1;e[1].push_back(y);}q.push(y);}}}}void dfs(int u){in[u]=++_index;for(int i=0;i<e[u].size();i++) dfs(e[u][i]);out[u]=++_index;}namespace BIT{int c[N*2];int lowbit(int x){ return x&(-x); }void add(int x,int ad){while(x<=_index){c[x]+=ad;x+=lowbit(x);}}int sum(int x){int res=0;while(x){res+=c[x];x-=lowbit(x);}return res;}}void print(){int i,j=1,now=0;sort(que+1,que+m+1);for(i=0;i<len;i++){if(str[i]=='B'){BIT::add(in[now+2],-1);now=pnt[now+2]-2;}else if(str[i]=='P');else{now=i;BIT::add(in[now+2],1);}while(que[j].b-2==i) {ans[que[j].id]=BIT::sum(out[que[j].a])-BIT::sum(in[que[j].a]-1);j++;}}for(int i=1;i<=m;i++) printf("%d\n",ans[i]);}int main(){init();bfs();dfs(1);print();return 0;}


0 0
原创粉丝点击