洛谷P2414  阿狸的打字机【AC自动机】【fail树】【dfs序】【树状数组】居然真的遇上了这种蔡队题。瑟瑟发抖。

题目背景

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

题目描述

打字机上只有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。

洛谷P2414  阿狸的打字机【AC自动机】【fail树】【dfs序】【树状数组】

 

题意:

给n个字符串问每次有m个询问,问第x个字符串在第y个字符串中出现了几次。

思路:

最开始是暴力建树,在字符串的结尾标记序号,然后每次询问暴力在树上查找。40分TLE

后来去看题解。题解看了无敌久。

实际上我们可以发现我们每次都是沿着AC自动机的fail指针在跳,在y中匹配x就是在属于y字符串的节点中能找到多少个节点可以跳到x的结束节点。

那么我们可以把原本的边都删去只保留fail指针,这就是AC自动机上的fail树。

把fail指针的方向反过来,其实就是找以x为根的树中有多少个节点是属于y的。

但是查询有很多组,暴力查询还是不可以的。由于每次查询我们需要去标记y节点,查询完了y节点的标记要删去。所以可以考虑先把所有查询排个序,把所有y相同的放在一起进行查询。并且我们处理出查询中某个x的下标区间,当dfs过程中访问到了这个x的结束节点就同时更新这些查询的答案。

建树的过程中先记下对应序号的字符串的结束节点下标和父亲节点,遇到“B”我们就回退到父亲节点,遇到“P”就打结束标记。

然后获取fail指针,并用fail指针建边,跑一遍dfs序,得到以x为根的子树的区间。

对排好序的问题,我们预处理出所有以y为第二个参数的查询的编号区间。

用树状数组维护子树和,dfs查询子树和,当访问到y的结尾时,说明这一组y完成了打标记工作,可以去求子树和了。那么就更新一下这一组查询的答案。然后要记得将这段子树的值-1

最后重新将答案映射会原来的顺序输出。

 

暴力40分代码:

  1 #include <iostream>
  2 #include <set>
  3 #include <cmath>
  4 #include <stdio.h>
  5 #include <cstring>
  6 #include <algorithm>
  7 #include <vector>
  8 #include <queue>
  9 #include <map>
 10 using namespace std;
 11 typedef long long LL;
 12 #define inf 0x7f7f7f7f
 13 
 14 int n, m;
 15 const int maxn = 1e5 + 5;
 16 
 17 struct Tree{
 18     int fail;//失配指针
 19     int vis[26];//子节点位置
 20     int ed = -1;
 21 }AC[maxn];
 22 string s[maxn];
 23 int tot = 0, cnt = 0;
 24 
 25 void build(string sss, int id)
 26 {
 27     //cout<<sss<<endl;
 28     int len = sss.length();
 29     int now = 0;//字典树当前指针
 30     for(int i = 0; i < len; i++){
 31         if(AC[now].vis[sss[i] - 'a'] == 0){
 32             AC[now].vis[sss[i] - 'a'] = ++tot;
 33         }
 34         now = AC[now].vis[sss[i] - 'a'];
 35     }
 36     AC[now].ed = id;
 37 }
 38 
 39 void get_fail()
 40 {
 41     queue<int> que;
 42     for(int i = 0; i < 26; i++){
 43         if(AC[0].vis[i] != 0){
 44             AC[AC[0].vis[i]].fail = 0;
 45             que.push(AC[0].vis[i]);
 46         }
 47     }
 48     while(!que.empty()){
 49         int u = que.front();
 50         que.pop();
 51         for(int i = 0; i < 26; i++){
 52             if(AC[u].vis[i] != 0){
 53                 AC[AC[u].vis[i]].fail = AC[AC[u].fail].vis[i];
 54                 que.push(AC[u].vis[i]);
 55             }
 56             else{
 57                 AC[u].vis[i] = AC[AC[u].fail].vis[i];
 58             }
 59         }
 60     }
 61 }
 62 
 63 int AC_query(int x, int y)
 64 {
 65     int leny = s[y].length();
 66     int now = 0, ans = 0;
 67     for(int i = 0; i < leny; i++){
 68         now = AC[now].vis[s[y][i] - 'a'];
 69         for(int t = now; t; t = AC[t].fail){
 70             if(AC[t].ed == x){
 71                 ans++;
 72             }
 73         }
 74     }
 75     return ans;
 76 }
 77 
 78 int main()
 79 {
 80     string str;
 81     char tmp[maxn];
 82     cin>>str;
 83     int len = str.length(), j = 0;
 84     for(int i = 0; i < len; i++){
 85         if(str[i] == 'B'){
 86             tmp[j] = 0;
 87             j--;
 88         }
 89         else if(str[i] == 'P'){
 90 
 91             s[cnt] = tmp;
 92             //cout<<s[cnt]<<endl;
 93             build(s[cnt], cnt);cnt++;
 94         }
 95         else{
 96             tmp[j++] = str[i];
 97         }
 98     }
 99     AC[0].fail = 0;
100     get_fail();
101     scanf("%d", &m);
102     while(m--){
103         int x, y;
104         scanf("%d %d", &x, &y);
105         //cout<<s[x - 1]<<" "<<s[y - 1]<<endl;
106         cout<<AC_query(x - 1, y - 1)<<endl;
107     }
108     //cout<<s[maxid]<<endl;
109     //cout<<AC_query(s)<<endl;
110     return 0;
111 }
View Code

相关文章:

  • 2021-09-07
  • 2022-02-04
  • 2021-11-12
  • 2021-10-14
  • 2021-08-30
  • 2021-11-06
  • 2022-12-23
猜你喜欢
  • 2021-12-29
  • 2022-01-03
  • 2021-06-15
  • 2022-01-04
  • 2021-07-26
  • 2021-09-11
  • 2021-08-27
相关资源
相似解决方案