BZOJ2434-[Noi2011]阿狸的打字机(AC自动机(fail树)+离线+树状数组)

Posted konjak魔芋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2434-[Noi2011]阿狸的打字机(AC自动机(fail树)+离线+树状数组)相关的知识,希望对你有一定的参考价值。

Description

 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和\'B\'、\'P\'两个字母。

经阿狸研究发现,这个打字机是这样工作的:

l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。

l 按一下印有\'B\'的按键,打字机凹槽中最后一个字母会消失。

l 按一下印有\'P\'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。

例如,阿狸输入aPaPBbP,纸上被打印的字符如下:

a

aa

ab

我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。

阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

Input

 输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

第二行包含一个整数m,表示询问个数。

接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

Output

 输出m行,其中第i行包含一个整数,表示第i个询问的答案。

Sample Input

aPaPBbP

3

1 2

1 3

2 3

Sample Output

2

1

0

HINT

 1<=N<=10^5


1<=M<=10^5

输入总长<=10^5

 

【分析】

  •    这道题是用AC自动机里的fail指针连成的树做的。
  •   用到fail树。
  •   首先有一个朴素算法就是找到第y个单词在trie树上的路径然后沿着每一个点的fail指针走,如果找到x就加1(想想fail指针建立的过程)。
  •   由此可以运用逆向思维,以x为根的子树沿着fail指针倒着走能找到多少个y路径上的点就说明x在y上出现过几次。每次都dfs找一遍,用树状数组维护,这样可以得到70分。
  •   同时这是一个离线算法,一遍dfs,遇到一个结束标记,就做一下这个串的询问,插一个点在树状数组+1,离开这个点时-1。
  •   对于树上每个点只插入一次,时间复杂度就得到了保证。

 

有一个很详细的题解:http://blog.csdn.net/huzecong/article/details/7769988

 

代码如下:(丑)

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 100100
  9 #define Maxl 100010
 10 
 11 char s[Maxl];
 12 int p[Maxn];
 13 
 14 struct hp
 15 {
 16     int x,y,next,id,ans;
 17 }qy[Maxn];int al;
 18 
 19 struct node
 20 {
 21     int son[30],cnt,fail;
 22     int num,rt,fa,st;
 23 }t[Maxn];int tot;
 24 
 25 int first[Maxn],c[Maxn];
 26 
 27 bool cmp(hp x,hp y) {return p[x.y]<p[y.y];}
 28 bool cmp2(hp x,hp y) {return x.id<y.id;}
 29 
 30 void ins(int x,int y)
 31 {
 32     qy[++al].x=x;qy[al].y=y;
 33     qy[al].next=first[x];first[x]=al;
 34 }
 35 
 36 void upd(int x,int f)
 37 {
 38     t[x].cnt=0;t[x].fa=f;t[x].st=0;
 39     memset(t[x].son,0,sizeof(t[x].son));
 40 }
 41 
 42 void read_trie()
 43 {
 44     scanf("%s",s+1);
 45     int len=strlen(s+1);
 46     memset(p,0,sizeof(p));
 47     int now=0;int ql=0;tot=0;
 48     for(int j=1;j<=len;j++)
 49     {
 50         if(s[j]>=\'a\'&&s[j]<=\'z\')
 51         {
 52             int ind=s[j]-\'a\'+1;
 53             if(!t[now].son[ind]) 
 54              t[now].son[ind]=++tot,upd(tot,now); 
 55             now=t[now].son[ind];
 56             if(j==len) t[now].cnt++;
 57         }
 58         else if(s[j]==\'B\') now=t[now].fa;
 59         else p[++ql]=now;
 60     }
 61 }
 62 
 63 queue<int > q;
 64 void build_AC()
 65 {
 66     int i,j,x,y;
 67     while(!q.empty()) q.pop();
 68     q.push(0);
 69     while(!q.empty())
 70     {
 71         x=q.front();
 72         y=t[x].fail;
 73         for(j=1;j<=26;j++)
 74         {
 75             if(t[x].son[j])
 76             {
 77                 q.push(t[x].son[j]);
 78                 t[t[x].son[j]].fail=x?t[y].son[j]:x;
 79                 ins(t[t[x].son[j]].fail,t[x].son[j]);
 80             }
 81             else t[x].son[j]=t[y].son[j];
 82         }
 83         q.pop();
 84     }
 85 }
 86 
 87 void dfs(int x)
 88 {
 89     t[x].num=++al;t[x].rt=t[x].num;
 90     for(int i=first[x];i;i=qy[i].next)
 91       dfs(qy[i].y),t[x].rt=t[qy[i].y].rt;
 92 }
 93 
 94 void add(int x,int y)
 95 {
 96     for(int i=x;i<=tot+1;i+=i&(-i))
 97      c[i]+=y;
 98 }
 99 
100 int getsum(int x)
101 {
102     int ans=0;
103     for(int i=x;i>=1;i-=i&(-i))
104         ans+=c[i];
105     return ans;
106 }
107 
108 void dfs2(int x)
109 {
110     add(t[x].num,1);
111     if(t[x].st!=0)
112     {
113         for(int i=t[x].st;;i++)
114         {
115             if(p[qy[i].y]!=x) break;
116             qy[i].ans=getsum(t[p[qy[i].x]].rt)-getsum(t[p[qy[i].x]].num-1);
117         }
118     }
119     for(int i=1;i<=26;i++) if(t[x].son[i]&&t[t[x].son[i]].fa==x)
120     {
121         dfs2(t[x].son[i]);
122     }
123     add(t[x].num,-1);
124 }
125 
126 void init()
127 {
128     memset(first,0,sizeof(first));
129     al=0;
130     read_trie();
131     build_AC();al=0;
132     dfs(0);
133     int m;
134     scanf("%d",&m);
135     for(int i=1;i<=m;i++) {scanf("%d%d",&qy[i].x,&qy[i].y);qy[i].id=i;}
136     sort(qy+1,qy+1+m,cmp);
137     qy[0].y=0;
138     for(int i=1;i<=m;i++) 
139       if(p[qy[i].y]!=p[qy[i-1].y]) t[p[qy[i].y]].st=i;
140       else t[p[qy[i].y]].st=t[p[qy[i-1].y]].st;
141     memset(c,0,sizeof(c));
142     dfs2(0);
143     sort(qy+1,qy+1+m,cmp2);
144     for(int i=1;i<=m;i++) printf("%d\\n",qy[i].ans);
145 }
146 
147 int main()
148 {
149     init();
150     return 0;
151 }
[BZOJ2434]

 

2016-06-16 16:55:20

以上是关于BZOJ2434-[Noi2011]阿狸的打字机(AC自动机(fail树)+离线+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2434: [Noi2011]阿狸的打字机

[bzoj 2434][Noi2011]阿狸的打字机

bzoj 2434 [Noi2011]阿狸的打字机 ac

Bzoj2434 [Noi2011]阿狸的打字机

bzoj2434: [Noi2011]阿狸的打字机

bzoj 2434 [Noi2011]阿狸的打字机(fail树+离线处理+BIT)