【BZOJ 2434】 [Noi2011]阿狸的打字机 fail树+树状数组

就是考了一个fail树的神奇应用我们建出fail树之后,发现我们就是在求y到根的路径上所有的点在以x为根的子树里的个数,这个我们离线后用树状数组+dfs序即可解决

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
const int N=100010;
char s[N];
struct Trie{
  int ch[26],fail,fa,deep;
}node[N];
std::vector<int> mem[N];
int sz;
struct V{
  int to,next;
}c[N];
struct VQ{
  int to,next,id;
}ques[N];
int head[N],t,num,ques_head[N],ques_t;
int belong[N],q[N],l[N],r[N],Time;
int T[N],ans[N],m,n;
inline int Q(int pos){
  int ret=0;
  for(;pos>0;pos-=pos&(-pos))
    ret+=T[pos];
  return ret;
}
inline void U(int pos,int key){
  for(;pos<=n;pos+=pos&(-pos))
    T[pos]+=key;
}
inline void add(int x,int y){
  c[++t].to=y,c[t].next=head[x],head[x]=t;
}
inline void ques_add(int x,int y,int z){
  ques[++ques_t].to=y,ques[ques_t].next=ques_head[x],ques_head[x]=ques_t,ques[ques_t].id=z;
}
void dfs(int x){
  l[x]=++Time;
  for(int i=head[x];i;i=c[i].next)
    dfs(c[i].to);
  r[x]=Time;
}
void dfs_(int x){
  U(l[x],1);
  for(int i=0;i<mem[x].size();i++)
    for(int j=ques_head[mem[x][i]];j;j=ques[j].next)
      ans[ques[j].id]=Q(r[belong[ques[j].to]])-Q(l[belong[ques[j].to]]-1);
  for(int i=0;i<26;i++)
    if(node[node[x].ch[i]].deep>node[x].deep)
      dfs_(node[x].ch[i]);
  U(l[x],-1);
}
int main(){
  scanf("%s",s);
  int now=0;
  for(int i=0;s[i];i++){
    if(s[i]=='P'){
      belong[++num]=now;
      mem[now].push_back(num);
      continue;
    }
    if(s[i]=='B'){
      now=node[now].fa;
      continue;
    }
    if(!node[now].ch[s[i]-'a'])node[now].ch[s[i]-'a']=++sz,node[sz].fa=now,node[sz].deep=node[now].deep+1;
    now=node[now].ch[s[i]-'a'];
  }
  n=sz+1;
  q[0]=0;
  for(int i=0,j=0;i<=j;i++)
    for(int l=0;l<26;l++)
      if(node[q[i]].ch[l]){
        q[++j]=node[q[i]].ch[l];
        node[q[j]].fail=q[i]?node[node[q[i]].fail].ch[l]:0;
        add(node[q[j]].fail,q[j]);
      }else
        node[q[i]].ch[l]=q[i]?node[node[q[i]].fail].ch[l]:0;
  dfs(0);
  scanf("%d",&m);
  for(int i=1,x,y;i<=m;i++)
    scanf("%d%d",&x,&y),ques_add(y,x,i);
  dfs_(0);
  for(int i=1;i<=m;i++)
    printf("%d\n",ans[i]);
  return 0;
} 

 

posted @ 2017-09-13 20:51  TS_Hugh  阅读(144)  评论(0编辑  收藏  举报