题目描述
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有 2828 个按键,分别印有 2626 个小写英文字母和 B、P 两个字母。经阿狸研究发现,这个打字机是这样工作的:
- 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
- 按一下印有
B的按键,打字机凹槽中最后一个字母会消失。 - 按一下印有
P的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入 aPaPBbP,纸上被打印的字符如下:
a aa ab
我们把纸上打印出来的字符串从 11 开始顺序编号,一直到 nn。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数 (x,y),打字机会显示第 x个打印的字符串在第 y 个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
题解
直接暴力显然是不行的,这里我们要利用AC自动机一些优良的性质
我们发现,一个AC自动机上的点A,它的fail指向B,那B对应的字符串一定是A的子串,同时我们发现把每个点的fail和它自己连边,就形成了一棵有根树
我们建出fail树后,问题就变成了y字符串对应的节点有多少个在x末尾对应的节点的子树内
那我们对树记录dfs序,用树状数组记录子树权值和就可以了
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<cstring>
5 #include<queue>
6 #include<vector>
7 #define fi first
8 #define se second
9 #define get(x) (x-'a')
10 using namespace std;
11 int read()
12 {
13 int k=0,f=1;char c=getchar();
14 for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
15 for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f;
16 }
17 const int N=200055;
18 typedef pair<int,int> P;
19 int n,m,sum,ans[N];
20 int cnt,ch[N][26],pos[N],fail[N];
21 int tot,fa[N],to[N],nextt[N],head[N];
22 int dfn,in[N],out[N];
23 int val[N];
24 char s[N];
25 vector<P> V[N];
26 queue<int> q;
27 void build()
28 {
29 for(int i=0;i<26;i++)
30 if(ch[0][i]) q.push(ch[0][i]);
31 while(!q.empty())
32 {
33 int u=q.front();q.pop();
34 for(int i=0;i<26;i++)
35 {
36 if(!ch[u][i]) ch[u][i]=ch[fail[u]][i];
37 else fail[ch[u][i]]=ch[fail[u]][i],q.push(ch[u][i]);
38 }
39 }
40 }
41 void add(int a,int b)
42 {
43 to[++tot]=b;
44 nextt[tot]=head[a];
45 head[a]=tot;
46 }
47 void dfs(int u)
48 {
49 in[u]=++dfn;
50 for(int i=head[u];i;i=nextt[i])
51 dfs(to[i]);
52 out[u]=dfn;
53 }
54 void ad(int a,int x) {for(;a<=dfn;a+=a&-a) val[a]+=x;}
55 int query(int a) {int ans=0;for(;a;a-=a&-a) ans+=val[a];return ans;}
56 int main()
57 {
58 scanf("%s",s+1);
59 n=strlen(s+1);
60 int now=0;
61 for(int i=1;i<=n;i++)
62 {
63 if(s[i]>='a'&&s[i]<='z')
64 {
65 if(!ch[now][get(s[i])]) cnt++,fa[cnt]=now,ch[now][get(s[i])]=cnt;
66 now=ch[now][get(s[i])];
67 }
68 else if(s[i]=='P') pos[++sum]=cnt;
69 else now=fa[now];
70 }
71 build();
72 for(int i=1;i<=cnt;i++)
73 add(fail[i],i);
74 dfs(0);
75 m=read();
76 for(int i=1;i<=m;i++)
77 {
78 int x,y;
79 x=read();y=read();
80 V[y].push_back(P(x,i));
81 }
82 now=0;sum=0;
83 for(int i=1;i<=n;i++)
84 {
85 if(s[i]>='a'&&s[i]<='z')
86 {
87 now=ch[now][get(s[i])];
88 ad(in[now],1);
89 }
90 else if(s[i]=='B')
91 {
92 ad(in[now],-1);
93 now=fa[now];
94 }
95 else
96 {
97 sum++;
98 for(int j=0;j<V[sum].size();j++)
99 ans[V[sum][j].se]+=query(out[pos[V[sum][j].fi]])-query(in[pos[V[sum][j].fi]]-1);
100 }
101 }
102 for(int i=1;i<=m;i++)
103 printf("%d\n",ans[i]);
104 return 0;
105 }
来源:https://www.cnblogs.com/waing/p/12178465.html