洛谷 P2414 [NOI2011]阿狸的打字机(Fail树 || DFS序 || 树状数组)

题目链接:https://www.luogu.com.cn/problem/P2414

 

由于Fail指针指向 “这个串的最长后缀”。而指向的那个点又是某个字符串的前缀。所以后缀的前缀是子串。 

 

 然后可以直接建出Fail树,建树时,如果$'B'$,那么就返回到这个节点的父亲,如果$'P'$,就把这一组存下来,vis和id是互为映射。

一遍DFS,处理出DFS序,然后便可以进行区间操作了。

用离线处理的方法,把每一组按照y排序,那么可以处理每一组询问,把同一种询问保存在一起。

比如询问第1个打印的字符串在第3个出现了几次,询问第2个字符串在第3个出现了几次,就可以把两个询问合并,变成:第3个打印的字符串中出现了几次第1个,几个第2个。

然后考虑每一个的贡献,可以用树状数组维护,如果有一个小写字母,那么便区间+1,每'B'一次,则区间-1。每'P'一次,则区间询问一次,求出答案,并离线记录。

 

AC代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 const int N=1000000+10;
  8 char str[N];
  9 int ch[N][26],fail[N],vis[N],fa[N];
 10 int cnt,num,dfn,tot;
 11 int L[N],R[N],head[N],id[N],ans[N],c[N];
 12 struct node{
 13     int to,next;
 14 }edge[N*2];
 15 struct Node{
 16     int x,y;
 17     int pos; 
 18 }q[N];
 19 bool cmp(Node aa,Node bb){
 20     return aa.y<bb.y;
 21 }
 22 void init(){
 23     num=dfn=cnt=tot=0;
 24     memset(vis,0,sizeof(vis));
 25     memset(head,-1,sizeof(head));
 26 }
 27 void add(int u,int v){
 28     edge[tot].to=v;
 29     edge[tot].next=head[u];
 30     head[u]=tot++;
 31 }
 32 void get_fail(){
 33     queue<int> q;
 34     for(int i=0;i<26;i++){
 35         if(ch[0][i]){
 36             add(0,ch[0][i]);
 37             q.push(ch[0][i]);
 38         }
 39     }
 40     while(!q.empty()){
 41         int u=q.front();q.pop();
 42         for(int i=0;i<26;i++){
 43             if(ch[u][i]){
 44                 fail[ch[u][i]]=ch[fail[u]][i];
 45                 q.push(ch[u][i]);
 46                 add(fail[ch[u][i]],ch[u][i]);
 47             }
 48             else ch[u][i]=ch[fail[u]][i];
 49         }
 50     }
 51 }
 52 void DFS(int u,int fa){
 53     L[u]=++dfn;
 54     for(int i=head[u];i!=-1;i=edge[i].next){
 55         int v=edge[i].to;
 56         if(v==fa) continue;
 57         DFS(v,u);
 58     }
 59     R[u]=dfn;
 60 }
 61 int lowbit(int x){
 62     return x&(-x);
 63 }
 64 void addval(int x,int val){
 65     while(x<=dfn){
 66         c[x]+=val;
 67         x+=lowbit(x);
 68     }
 69 }
 70 int query(int x){
 71     int ans=0;
 72     while(x){
 73         ans+=c[x];
 74         x-=lowbit(x);
 75     }
 76     return ans;
 77 }
 78 int main(){
 79     scanf("%s",str);
 80     int len=strlen(str);
 81     init();
 82     int u=0;
 83     for(int i=0;i<len;i++){
 84         if(str[i]>='a'&&str[i]<='z'){
 85             int id=str[i]-'a';
 86             if(!ch[u][id]) ch[u][id]=++cnt;
 87             fa[cnt]=u;
 88             u=ch[u][id];
 89         }
 90         else if(str[i]=='B') u=fa[u];
 91         else vis[u]=++num,id[num]=u;
 92     }
 93     get_fail();
 94     DFS(0,-1);
 95     int n;
 96     scanf("%d",&n);
 97     for(int i=1;i<=n;i++){
 98         scanf("%d%d",&q[i].x,&q[i].y);
 99         q[i].pos=i; 
100     }
101     sort(q+1,q+n+1,cmp);
102     num=0;
103     int j=0,root=0;
104     for(int i=0;i<len;i++){
105         if(str[i]=='B') addval(L[root],-1),root=fa[root];
106         else if(str[i]=='P'){
107             num++;
108             while(j<n&&q[j+1].y==num){
109                 j++;
110                 int v=id[q[j].x];
111                 ans[q[j].pos]=query(R[v])-query(L[v]-1);
112             }
113         }
114         else{
115             int id=str[i]-'a';
116             root=ch[root][id];
117             addval(L[root],1);
118         }
119     }
120     for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
121     return 0;
122 }
AC代码

 

posted @ 2020-03-07 09:27  dfydn  阅读(130)  评论(0编辑  收藏  举报