bzoj2434 [Noi2011]阿狸的打字机(AC自动机+fail树+树状数组)
2018-03-23 11:43
295 查看
多次询问一个串x在另一个串y中的出现次数。
我们先建出ACAM,考虑如何做这件事,就是询问y有多少个节点沿着fail指针能找到x。但是这样太慢,我们不妨反向思考,就是求x沿着反向的fail指针能找到几个y的节点。
我们建出fail树(fail指针没有环 每个节点只有一个出度 那么反向之后显然是一棵树 x沿着反向的fail指针所能到达的节点就是x所在的子树)。
所以现在就是询问x的子树中有多少个y的节点。我们可以求出dfs序,转化为区间求和问题。
由于这道题的特殊性质,加入的字符串顺序是有规律的,我们可以把询问离线,按y从小到大排序,然后扫一遍串S来更新BIT,假设我们现在在节点p。
对于B:在BIT中删掉节点p,返回到fa[p]
对于P:出现了一个新的字符串tot,处理所有y=tot的询问。
对于加字符:走到对应节点p,在BIT中加入节点p。
复杂度O(nlogn)
我们先建出ACAM,考虑如何做这件事,就是询问y有多少个节点沿着fail指针能找到x。但是这样太慢,我们不妨反向思考,就是求x沿着反向的fail指针能找到几个y的节点。
我们建出fail树(fail指针没有环 每个节点只有一个出度 那么反向之后显然是一棵树 x沿着反向的fail指针所能到达的节点就是x所在的子树)。
所以现在就是询问x的子树中有多少个y的节点。我们可以求出dfs序,转化为区间求和问题。
由于这道题的特殊性质,加入的字符串顺序是有规律的,我们可以把询问离线,按y从小到大排序,然后扫一遍串S来更新BIT,假设我们现在在节点p。
对于B:在BIT中删掉节点p,返回到fa[p]
对于P:出现了一个新的字符串tot,处理所有y=tot的询问。
对于加字符:走到对应节点p,在BIT中加入节点p。
复杂度O(nlogn)
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; #define ll long long #define N 100010 #define inf 0x3f3f3f3f inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } int n=0,rt,son [26],fail ,h ,num=1,fa ,id ,m,nn=0; int in ,out ,dfn=0,c ,ans ; char s ; struct edge{ int to,next; }data ; struct quer{ int x,y,id; }qq ; inline bool cmp(quer a,quer b){return a.y<b.y;} inline void adde(int x,int y){ data[++num].to=y;data[num].next=h[x];h[x]=num; } inline void add(int x,int val){for(;x<=n;x+=x&-x) c[x]+=val;} inline int ask(int x){int res=0;for(;x;x-=x&-x) res+=c[x];return res;} inline void buildTrie(){ int p=rt=++n,len=strlen(s+1); for(int i=0;i<26;++i) son[0][i]=rt; for(int i=1;i<=len;++i){ if(s[i]=='B'){p=fa[p];continue;} if(s[i]=='P'){id[++nn]=p;continue;} int &y=son[p][s[i]-'a'];if(!y) y=++n;fa[y]=p;p=y; } } inline void buildAC(){ queue<int>q;q.push(rt); while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<26;++i){ int &y=son[x][i]; if(!y){y=son[fail[x]][i];continue;}q.push(y); fail[y]=son[fail[x]][i];adde(fail[y],y); } } } void dfs(int x){ in[x]=++dfn; for(int i=h[x];i;i=data[i].next) dfs(data[i].to); out[x]=dfn; } int main(){ // freopen("a.in","r",stdin); scanf("%s",s+1);buildTrie();buildAC();dfs(1);m=read(); for(int i=1;i<=m;++i) qq[i].x=read(),qq[i].y=read(),qq[i].id=i; sort(qq+1,qq+m+1,cmp);int len=strlen(s+1),now=1,p=rt,tot=0; for(int i=1;i<=len;++i){ if(s[i]=='B'){add(in[p],-1);p=fa[p];continue;} if(s[i]=='P'){ ++tot;while(now<=m&&qq[now].y==tot){ int x=id[qq[now].x];ans[qq[now].id]=ask(out[x])-ask(in[x]-1);++now; }continue; }p=son[p][s[i]-'a'];add(in[p],1); }for(int i=1;i<=m;++i) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- 【bzoj2434】 Noi2011—阿狸的打字机
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
- BZOJ2434_[Noi2011]阿狸的打字机(AC自动机+树状数组+dfs序)
- bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)
- 【BZOJ2434-[Noi2011]】阿狸的打字机(AC自动机(fail树)+离线+树状数组)
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
- ●BZOJ 2434: [Noi2011]阿狸的打字机
- bzoj 2434 [Noi2011]阿狸的打字机 [AC自动机+树状数组]
- 【BZOJ2434】阿狸的打字机(NOI2011)-AC自动机+树状数组
- bzoj2434: [Noi2011]阿狸的打字机
- 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序
- BZOJ2434【NOI2011】阿狸的打字机 <AC自动机+Fail树+树状数组>
- BZOJ 2434 [Noi2011]阿狸的打字机
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
- NOI2011 阿狸的打字机(BZOJ2434) 题解
- 【dfs序+AC自动机+树状数组】BZOJ2434-[Noi2011]阿狸的打字机
- BZOJ 2434 [Noi2011] 阿狸的打字机 Fail树
- fail树 【Noi2011】 阿狸的打字机 bzoj2434