标签:bzoj2434 noi2011 阿狸的打字机 题解 ac自动机
转载请注明出处233:http://blog.csdn.net/vmurder/article/details/42875307
这是一道神题。
首先我们需要建立AC自动机,然后再建个Fail树,之后发现
如果询问a串在b串中出现了几次,那么只需要看b串在AC自动机上所有的节点中有多少个节点,在a串的结束节点在Fail树上的子树中就可以了。
然后这样做就很可以了,但是仍然不能AC,
这时我们只需要按照Fail树的dfs序建立数据结构(我写了树状数组)进行区间查询就好了。
这时对于以上的b串,我们按照dfs序扫一遍(按照输入时的字符串就是天然的优越dfs序),然后每转移一个节点,就在数据结构上加加减减、、
然后对于每个‘B’,挂链询问中问了哪些‘A’在其中出现了多少次,树状数组O(logn)查一次就好了。
单点修改区间查询,时间复杂度mlogn。
代码:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 101000 #define MAX 220000 #define T 26 using namespace std; struct FAIL { int v[N],next[N],head[N],cnt; void cls() { cnt=0; memset(head,0,sizeof head); } void add(int u,int _v) { v[++cnt]=_v; next[cnt]=head[u]; head[u]=cnt; } int in[N],out[N],dfn; void build_dfn(int x=0) { in[x]=++dfn; for(int i=head[x];i;i=next[i]) build_dfn(v[i]); out[x]=++dfn; } }Fail; struct FENWICK //树状数组 { int fenwick[MAX]; inline void add (int x,int w) { for(x=Fail.in[x];x<MAX;x+=(x&-x)) fenwick[x]+=w; } inline int query(int x) { int ans=0,temp=x; for(x=Fail.out[temp] ;x;x-=(x&-x))ans+=fenwick[x]; for(x=Fail.in[temp]-1;x;x-=(x&-x))ans-=fenwick[x]; return ans; } }fw; struct TRIE { int pa[N],next[N][T],fail[N]; int end[N],crs[N]; int root,cnt,id; char s[N]; void build_trie() // 建立Trie { scanf("%s",s); int i,x=root=0,alp; for(i=0;s[i];i++) { if(s[i]=='P')end[x]=++id,crs[id]=x; else if(s[i]=='B')x=pa[x]; else { alp=s[i]-'a'; if(!next[x][alp])next[x][alp]=++cnt,pa[cnt]=x; x=next[x][alp]; } } } void build_fail() // 建立AC自动机 { queue<int>q; q.push(root); int i,u,v,temp; while(!q.empty()) { u=q.front(),q.pop(); for(i=0;i<T;i++)if(v=next[u][i]) { if(u==root)fail[v]=root; else { temp=fail[u]; while(temp&&!next[temp][i])temp=fail[temp]; fail[v]=next[temp][i]; } q.push(v); Fail.add(fail[v],v); } } } int v[N],nxt[N],head[N]; void add(int u,int _v) // 询问离线 { v[++cnt]=_v; nxt[cnt]=head[u]; head[u]=cnt; } int m,fians[N]; void input() // 输入询问 { int a,b; scanf("%d",&m); cnt=0; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); add(b,a); } } void query(int pdd) { for(int i=head[pdd];i;i=nxt[i]) fians[i]=fw.query(crs[v[i]]); } void work() // 遍历B串 { int i,x=root=0,alp,now; for(i=0;s[i];i++) { if(s[i]=='P')query(end[x]); else if(s[i]=='B')fw.add(x,-1),x=pa[x]; else { alp=s[i]-'a'; x=next[x][alp]; fw.add(x,1); } } return ; } void output() // 输出答案 {for(int i=1;i<=m;i++)printf("%d\n",fians[i]);} }Trie; int main() { // freopen("my.in","r",stdin); // freopen("my.out","w",stdout); Trie.build_trie(); Trie.build_fail(); Fail.build_dfn(); Trie.input(); Trie.work(); Trie.output(); return 0; }
【BZOJ2434】【NOI2011】阿狸的打字机 AC自动机
标签:bzoj2434 noi2011 阿狸的打字机 题解 ac自动机
原文地址:http://blog.csdn.net/vmurder/article/details/42875307