题意:给出阿狸的打字顺序(小写字母是写入,‘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 0x3f3f3f3f using 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; }