BZOJ2434: [Noi2011]阿狸的打字机
2018-02-21 15:50
344 查看
阿狸的打字过程实际上是在建一个trie树,对这棵trie建立ac自动机的fail树后,问第x个串在第y个串中出现了多少次,相当于问y串有多少个前缀,在fail树中位于x的子树里
到这里其实好像离线一下就可以了?但还有另一种资瓷在线询问的做法
我们不可能对y串的每个前缀处理,因为这个trie树的建立可以让所有串的总长是n^2级别的
但其实在trie树上这样走造字符串,很多串有着很长的LCP,比如在t1时刻我从节点x走了下去,在t2时刻退出了节点x,那么t1~t2时刻造出的所有字符串的前缀都有x,我们在trie树上走进一个节点时记录当前在造第x个串,离开时若当前在造第y个串,那么x就是串[x,y)的前缀,x的子树中[x,y)的出现次数就+1,这样得到的区间[x,y)的数量是O(n)个的,对每个点p的[x,y),在p的线段树上对[x,y)区间+1,然后在fail树上线段树合并,就可以求出每个点p的子树内每个串的出现次数,就可以O(log)做到在线询问了
code:
到这里其实好像离线一下就可以了?但还有另一种资瓷在线询问的做法
我们不可能对y串的每个前缀处理,因为这个trie树的建立可以让所有串的总长是n^2级别的
但其实在trie树上这样走造字符串,很多串有着很长的LCP,比如在t1时刻我从节点x走了下去,在t2时刻退出了节点x,那么t1~t2时刻造出的所有字符串的前缀都有x,我们在trie树上走进一个节点时记录当前在造第x个串,离开时若当前在造第y个串,那么x就是串[x,y)的前缀,x的子树中[x,y)的出现次数就+1,这样得到的区间[x,y)的数量是O(n)个的,对每个点p的[x,y),在p的线段树上对[x,y)区间+1,然后在fail树上线段树合并,就可以求出每个点p的子树内每个串的出现次数,就可以O(log)做到在线询问了
code:
#include<set> #include<map> #include<deque> #include<queue> #include<stack> #include<cmath> #include<ctime> #include<bitset> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<climits> #include<complex> #include<iostream> #include<algorithm> #define ll long long using namespace std; const int maxn = 210000; int n,m,to[maxn]; int ans[maxn],qi[maxn]; vector<int>query[maxn]; struct segment { int seg[maxn*25],lc[maxn*25],rc[maxn*25],root[maxn],cnt; int lx,rx; void add(int &x,const int l,const int r) { if(rx<l||r<lx) return; if(!x) x=++cnt; if(lx<=l&&r<=rx) { seg[x]++; return; } int mid=l+r>>1; add(lc[x],l,mid); add(rc[x],mid+1,r); } void merge(int &x,const int y) { if(!y) return; if(!x) { x=y; return; } seg[x]+=seg[y]; merge(lc[x],lc[y]); merge(rc[x],rc[y]); } int loc,c; int query(const int x,const int l,const int r) { c+=seg[x]; if(l==r||!x) return c; int mid=l+r>>1; if(loc<=mid) return query(lc[x],l,mid); else return query(rc[x],mid+1,r); } }seg; struct interval{int l,r;}; vector<interval>V[maxn]; struct edge{int y,nex;}a[maxn]; int len,fir[maxn]; inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;} void dfs(const int x) { for(int i=0;i<V[x].size();i++) { const interval now=V[x][i]; seg.lx=now.l,seg.rx=now.r-1; if(seg.lx<=seg.rx) seg.add(seg.root[x],1,n); } for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) { dfs(y); seg.merge(seg.root[x],seg.root[y]); } for(int i=0;i<query[x].size();i++) { int j=query[x][i],y=qi[j]; seg.loc=y; seg.c=0; ans[j]=seg.query(seg.root[x],1,n); } } struct trie{int son[26],fa,fail,las;}tr[maxn]; int root,tot; char str[maxn]; queue<int>q; void build_trie() { int x=root,len=strlen(str); n=1; for(int i=0;i<len;i++) { char cc=str[i]; if(cc=='P') to[++n]=x; else if(cc=='B') V[x].push_back((interval){tr[x].las,n}),x=tr[x].fa; else { int c=cc-'a'; if(!tr[x].son[c]) tr[tr[x].son[c]=++tot].fa=x; x=tr[x].son[c]; tr[x].las=n; } } while(1) { V[x].push_back((interval){tr[x].las,n}); if(x==root) break; x=tr[x].fa; } q.push(root); while(!q.empty()) { const int x=q.front(); q.pop(); int fl=tr[x].fail; for(int i=0;i<26;i++) { int &y=tr[x].son[i]; if(y) { if(x!=root) tr[y].fail=tr[fl].son[i]; q.push(y); } else y=tr[fl].son[i]; } } } void build_failtree() { len=0; //memset(fir,0,sizeof fir); for(int i=1;i<=tot;i++) ins(tr[i].fail,i); } int main() { scanf("%s",str); build_trie(); build_failtree(); scanf("%d",&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); qi[i]=y; query[to[x+1]].push_back(i); } dfs(0); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- [bzoj2434] [Noi2011]阿狸的打字机
- 【AC自动机】 BZOJ 2434 [Noi2011]阿狸的打字机
- BZOJ 2434: [Noi2011]阿狸的打字机【AC自动机,fail树.dfs序,树状数组
- bzoj2434【NOI2011】阿狸的打字机
- bzoj 2434: [Noi2011]阿狸的打字机
- [bzoj2434][ac自动机][线段树合并][Noi2011]阿狸的打字机
- BZOJ 2434([Noi2011]阿狸的打字机-AC自动机-Fail树)
- BZOJ 2434 [Noi2011]阿狸的打字机
- bzoj2434 [Noi2011]阿狸的打字机(AC自动机+fail树+树状数组)
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
- bzoj2434 阿狸的打字机[NOI2011] AC自动机+树状数组
- bzoj2434 阿狸的打字机 noi2011
- 【bzoj2434】[Noi2011]阿狸的打字机 AC自动机+Dfs序+树状数组
- bzoj 2434: [Noi2011]阿狸的打字机
- ●BZOJ 2434: [Noi2011]阿狸的打字机
- Bzoj2434 [Noi2011]阿狸的打字机
- BZOJ_2434_[Noi2011]阿狸的打字机_AC自动机+出栈入栈序+树状数组
- bzoj2434 [Noi2011]阿狸的打字机 ( AC自动机 & fail树 + 树状数组 + dfs序 )
- BZOJ 2434: [Noi2011]阿狸的打字机
- 2434: [Noi2011]阿狸的打字机 - BZOJ