BZOJ_2434
fail树上建可持久化树。
根据原题中给定的输入跑就可以跑出一颗trie树,然后对这个trie数建fail树。我最开始的思路错了:A串在B串中出现的次数就是看B中有多少节点可以直接或者说间接的指向A的子树。举个反例:A = aaa,设A的子树是一个点为b,B = aaab,那么B将会有两个指针指向A的子树,出错了。正确姿势应该是对fail树的DFS序修改,我的做法是可持久化,在AC自动机上的树跑DFS,每到一个点对它的fail的子树进行区间修改,查询的时候就查询子树和就好了(我真是太蠢了)
#include <cstdio> #include <iostream> #include <cstring> using namespace std; const int N = 100003; char a[N]; int t1,t2,q,haha1,haha2,biao[N]; int first[N],to[N*2],next_[N*2],eg; inline void addedge(int x,int y) { next_[++eg] = first[x]; first[x] = eg; to[eg] = y; } struct AC { AC* fail; AC* ch[26]; AC* pre; int key; AC() { for(int i = 0 ; i < 26 ; ++i) ch[i] = NULL; pre = fail = NULL; key = 0; } }*R,dizhi1[N],*bfs[N]; struct tree1 { tree1* lson; tree1* rson; int sum; tree1() { lson = rson = NULL; sum = 0; } }*root[N],dizhi2[N*20]; inline void get_fail() { bfs[1] = R; int h = 0 , t = 1; do { AC* u = bfs[++h]; for(int i = 0 ; i < 26 ; ++i) { if(u->ch[i]==NULL) continue; if(u==R) { u->ch[i]->fail = R; addedge(R->key,u->ch[i]->key); bfs[++t] = u->ch[i]; continue; } AC* temp = u->fail; while(temp!=R&&temp->ch[i]==NULL) temp = temp->fail; if(temp->ch[i]!=NULL) { u->ch[i]->fail = temp->ch[i]; addedge(temp->ch[i]->key,u->ch[i]->key); } else { u->ch[i]->fail = R; addedge(R->key,u->ch[i]->key); } bfs[++t] = u->ch[i]; } }while(h<t); } int st[N],ed[N],tt; inline void dfs(int u) { st[u] = ++tt; for(int i = first[u] ; i ; i = next_[i]) dfs(to[i]); ed[u] = tt; } inline void insert(tree1* tree,int l,int r,int pos,tree1* last) { if(l==r) { tree->sum = last==NULL?1:last->sum+1; return; } int mid = (l+r) >>1; if(pos <= mid) { if(last!=NULL && last->rson!=NULL) tree->rson = last->rson; tree->lson = &dizhi2[++t2]; if(last!=NULL && last->lson!=NULL) insert(tree->lson,l,mid,pos,last->lson); else insert(tree->lson,l,mid,pos,NULL); } else { if(last!=NULL && last->lson!=NULL) tree->lson = last->lson; tree->rson = &dizhi2[++t2]; if(last!=NULL && last->rson!=NULL) insert(tree->rson,mid+1,r,pos,last->rson); else insert(tree->rson,mid+1,r,pos,NULL); } if(tree->lson!=NULL) tree->sum += tree->lson->sum; if(tree->rson!=NULL) tree->sum += tree->rson->sum; } inline void build(AC* u) { if(u!=R) { root[u->key] = &dizhi2[++t2]; insert(root[u->key],1,haha2,st[u->key],root[u->pre->key]); } for(int i = 0 ; i < 26 ; ++i) if(u->ch[i]!=NULL) build(u->ch[i]); } inline int query(tree1* tree,int l,int r,int x,int y) { if(x<=l && r<=y) return tree->sum; int mid = (l+r)>>1,q1 = 0,q2 = 0; if(!(y<l || mid<x) && tree->lson!=NULL) q1 = query(tree->lson,l,mid,x,y); if(!(y<mid+1||r<x) && tree->rson!=NULL) q2 = query(tree->rson,mid+1,r,x,y); return (q1+q2); } int main() { scanf("%s",a); int len = strlen(a); R = &dizhi1[++t1]; R->key = ++haha2; AC* now = R; for(int i = 0 ; i < len ; ++i) { if(a[i]=='B') { now = now->pre; continue; } if(a[i]=='P') { biao[++haha1] = now->key; continue; } int to = a[i] - 'a'; if(now->ch[to]==NULL) { now->ch[to] = &dizhi1[++t1]; now->ch[to]->pre = now; now->ch[to]->key = ++haha2; } now = now->ch[to]; } get_fail(); dfs(R->key); build(R); scanf("%d",&q); for(int i = 1,x,y ; i <= q ; ++i) { scanf("%d%d",&x,&y); printf("%d\n",query(root[biao[y]],1,haha2,st[biao[x]],ed[biao[x]])); } }