【NOI 2011】阿狸的打字机(AC自动机+fail树)

题目背景

阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。

题目描述

打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。经阿狸研究发现,这个打字机是这样工作的:

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

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

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

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

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

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

输入格式

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

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

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

输出格式

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

输入输出样例

输入 #1
  aPaPBbP
3
1 2
1 3
2 3
输出 #1
  2
1
0

说明/提示

数据范围:

对于100%的数据,n<=100000,m<=100000,第一行总长度<=100000

【题目大意】

给定一串字符串,其中包含一些特殊字符,代表一些操作,操作如下

1:B   消去凹槽中最后一个字符

2:P   打印出凹槽中所有字符

知识点:
  1.AC自动机

  2.对fail树的操作

注意:

  理解fail树的本质,因为没有弄清楚查了好久。

题解咕了

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<string>
  6 #include<vector>
  7 #include<queue>
  8 using namespace std;
  9 const int MAXN = 100010;
 10 int cnt, siz = 0;
 11 int exist[MAXN], last[MAXN];
 12 int fail[MAXN], tire[MAXN][27];
 13 vector<int>  fail_tree[MAXN];
 14 int ans_arr[MAXN];
 15 int in[2 * MAXN], out[2 * MAXN], tree[2 * MAXN];
 16 int lowbit(int n)
 17 {
 18     return (n&(-n));
 19 }
 20 int book[MAXN];
 21 int st[MAXN];
 22 int top = 0;
 23 int size_[MAXN];
 24 struct note
 25 {
 26     int pos;
 27     int x;
 28     //NOte(int a,int b):x(a),pos(b){}
 29 };
 30 vector<note> ask[MAXN];
 31 
 32 void insert(string s)
 33 {
 34     int u = 0;
 35     for (char c : s)
 36     {
 37         if (c == 'B')
 38         {
 39             u = fai[u];
 40         }
 41         else
 42         {
 43             if (c == 'P')
 44             {
 45                 siz++;
 46                 last[siz] = u;
 47             }
 48             else
 49             {
 50                 int i = c - 'a';
 51                 if (tire[u][i] == 0)
 52                 {
 53                     cnt++;
 54                     tire[u][i] = cnt;
 55                     fail[tire[u][i]] = u;
 56                 }
 57                 u = tire[u][i];
 58             }
 59         }
 60     }
 61     return;
 62 }
 63 void Get_Fail()
 64 {
 65     queue<int> que;
 66     for (int i = 0; i < 26; i++)
 67     {
 68         if (tire[0][i])
 69         {
 70             fail[tire[0][i]] = 0;
 71             que.push(tire[0][i]);
 72             fail_tree[0].push_back(tire[0][i]);
 73         }
 74     }
 75     while (!que.empty())
 76     {
 77         int u = que.front();
 78         que.pop();
 79         for (int i = 0; i < 26; i++)
 80         {
 81             int vis = tire[u][i];
 82             if (vis != 0)
 83             {
 84                 fail[vis] = tire[fail[u]][i];
 85                 que.push(vis);
 86                 fail_tree[fail[vis]].push_back(vis);
 87             }
 88             else
 89             {
 90                 tire[u][i] = tire[fail[u]][i];
 91             }
 92         }
 93     }
 94 
 95     return;
 96 }
 97 void Dfs(int num)
 98 {
 99     cnt++;
100     in[num] = cnt;
101     for (int t : fail_tree[num])
102     {
103         Dfs(t);
104     }
105     out[num] = cnt;
106     return;
107 }
108 void update(int x, int v)
109 {
110     for (int i = x; i < MAXN; i += lowbit(i))
111     {
112         tree[i] += v;
113     }
114     return;
115 }
116 int query(int x)
117 {
118     int ans = 0;
119     for (int i = x; i > 0; i -= lowbit(i))
120     {
121         ans += tree[i];
122     }
123     return ans;
124 }
125 int main()
126 {
127     int n;
128     string s;
129     memset(st, -1, sizeof(st));
130     cin >> s;
131     //printf("**\n");
132     insert(s);
133     //printf("**\n");
134     Get_Fail();
135     //printf("**\n");
136     cnt = 0;
137     Dfs(0);
138     //printf("**\n");
139     cin >> n;
140     for (int i = 1; i <= n; i++)
141     {
142         int x, y;
143         cin >> x >> y;
144         note tmp;
145         tmp.x = x, tmp.pos = i;
146         ask[y].push_back(tmp);
147         //printf("%d %d\n", ask[y][ask[y].size() - 1].x, ask[y][ask[y].size() - 1].pos);
148     }
149     int u = 0;
150     siz = 0;
151     //update(in[0], 1);
152     for (char c : s)
153         if (c == 'B')
154         {
155             update(in[u], -1);
156             u = fail[u];
157         }
158         else
159         {
160             if (c == 'P')
161             {
162                 siz++;
163                 for (int i = 0; i < (int)ask[siz].size(); i++)
164                 {
165                     int x = last[ask[siz][i].x];
166                     ans_arr[ask[siz][i].pos] = query(out[x]) - query(in[x] - 1);
167                 }
168             }
169             else
170             {
171                 int i = c - 'a';
172                 u = tire[u][i];
173                 update(in[u], 1);
174             }
175         }
176     for (int i = 1; i <= n; i++)
177     {
178         printf("%d\n", ans_arr[i]);
179     }
180     return 0;
181 }
P2414

 

posted @ 2019-07-24 10:14  rentu  阅读(215)  评论(0编辑  收藏  举报