https://www.lydsy.com/JudgeOnline/problem.php?id=2434

  1. 打字机上只有28个按键,分别印有26个小写英文字母和'B''P'两个字母。经阿狸研究发现,这个打字机是这样工作的:
  2.  
  3. ·输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
  4.  
  5. ·按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。
  6.  
  7. ·按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
  8.  
  9. 例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
  10.  
  11. a aa ab 我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1x,yn),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
  12.  
  13. 阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

题意

首先第一个想法一定是把所有单词插入到AC自动机并且保存所有N个单词的end结点位置,对于x,y串的询问,将y串end结点到根节点之间的所有结点跳一边fail指针,将经过的结点全部 + 1,查询一下x的结点保存的大小即可。

当然这是纯暴力的写法,我们考虑去优化。

首先把对于同一y的x,当然可以合并起来一起处理

其次对于y串包含x串,就意味着x被包含的次数为fail树上将y全部结点加入之后的子树和。

对于这一类动态的去维护子树和的行为,我们自然而然的想到dfs序,求出整颗fail树上的dfs序之后用树状数组动态的对于每个询问加入y串和查询然后删除y串一气呵成。

到了这一步看似已经稳如狗,可交上去依旧TLE

事实上仔细看题意里给出的字符串构造方式,我们就会发现这些字符串并不是毫无关联的字符串,换言之,在开始的insert里面,不需要每次都插入一个独立的字符串,而是只需要开一个now来模拟当前结点的位置,如果遇到P则直接返回now,如果遇到B则将now变为他的父节点,插入时就变为它指向的目标子结点。

不仅仅如此,即使在最后离线查询的时候,事实上也是不需要每次都动态的加入整个y串和删除y串的

只要模拟当前字符串的移动路线,每次遇到B的时候返回父节点并且删除当前结点在dfs序中的加成,遇到插入的时候就在树状数组中相应位置 + 1,每次查询就不用遍历y结点到根节点的所有结点了。

  1. #include <map>
  2. #include <set>
  3. #include <ctime>
  4. #include <cmath>
  5. #include <queue>
  6. #include <stack>
  7. #include <vector>
  8. #include <string>
  9. #include <cstdio>
  10. #include <cstdlib>
  11. #include <cstring>
  12. #include <sstream>
  13. #include <iostream>
  14. #include <algorithm>
  15. #include <functional>
  16. using namespace std;
  17. inline int read(){int now=;register char c=getchar();for(;!isdigit(c);c=getchar());
  18. for(;isdigit(c);now=now*+c-'',c=getchar());return now;}
  19. #define For(i, x, y) for(int i=x;i<=y;i++)
  20. #define _For(i, x, y) for(int i=x;i>=y;i--)
  21. #define Mem(f, x) memset(f,x,sizeof(f))
  22. #define Sca(x) scanf("%d", &x)
  23. #define Sca2(x,y) scanf("%d%d",&x,&y)
  24. #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
  25. #define Scl(x) scanf("%lld",&x);
  26. #define Pri(x) printf("%d\n", x)
  27. #define Prl(x) printf("%lld\n",x);
  28. #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
  29. #define LL long long
  30. #define ULL unsigned long long
  31. #define mp make_pair
  32. #define PII pair<int,int>
  33. #define PIL pair<int,long long>
  34. #define PLL pair<long long,long long>
  35. #define pb push_back
  36. #define fi first
  37. #define se second
  38. typedef vector<int> VI;
  39. const double eps = 1e-;
  40. const int maxn = 1e5 + ;
  41. const int maxm = 5e5 + ;
  42. const int INF = 0x3f3f3f3f;
  43. const int mod = 1e9 + ;
  44. int N,M,K;
  45. char mstr[maxn];
  46. char str[maxn];
  47. int Index[maxn];
  48.  
  49. //链式前向星
  50. struct Edge{
  51. int to,next;
  52. }edge[maxm];
  53. int head[maxm],TOT;
  54. void init(int n){
  55. for(int i = ; i < n; i ++) head[i] = -;
  56. TOT = ;
  57. }
  58. void add(int u,int v){
  59. edge[TOT].to = v;
  60. edge[TOT].next = head[u];
  61. head[u] = TOT++;
  62. }
  63. //AC自动机
  64. int nxt[maxm][],fail[maxm],tot,root,fa[maxm];
  65. int newnode(int f){
  66. for(int i = ; i < ; i ++) nxt[tot][i] = -;
  67. fa[tot] = f;
  68. return tot++;
  69. }
  70. void init(){
  71. tot = ;root = newnode();
  72. }
  73. void Build(){
  74. queue<int>Q; init(tot);
  75. for(int i = ; i < ; i ++){
  76. if(~nxt[root][i]){
  77. fail[nxt[root][i]] = root;
  78. add(root,nxt[root][i]);
  79. Q.push(nxt[root][i]);
  80. }else{
  81. nxt[root][i] = root;
  82. }
  83. }
  84. while(!Q.empty()){
  85. int u = Q.front(); Q.pop();
  86. for(int i = ; i < ; i ++){
  87. if(~nxt[u][i]){
  88. fail[nxt[u][i]] = nxt[fail[u]][i];
  89. add(nxt[fail[u]][i],nxt[u][i]);
  90. Q.push(nxt[u][i]);
  91. }else{
  92. nxt[u][i] = nxt[fail[u]][i];
  93. }
  94. }
  95. }
  96. }
  97. //dfs序
  98. int num = ;
  99. PII pos[maxm];
  100. void dfs(int t,int la){
  101. pos[t].fi = ++num;
  102. for(int i = head[t]; ~i; i = edge[i].next){
  103. int v = edge[i].to;
  104. if(v == la) continue;
  105. dfs(v,t);
  106. }
  107. pos[t].se = ++num;
  108. }
  109. //树状数组
  110. int tree[maxm * ];
  111. void tadd(int x,int t){
  112. for(;x <= num; x += x & -x) tree[x] += t;
  113. }
  114. int getsum(int x){
  115. int s = ;
  116. for(;x > ;x -= x & -x) s += tree[x];
  117. return s;
  118. }
  119.  
  120. struct Query{
  121. int x,y,id;
  122. }query[maxn];
  123. bool cmp(Query a,Query b){
  124. return a.y < b.y;
  125. }
  126. int ans[maxn];
  127.  
  128. int main(){
  129. //freopen("C.in","r",stdin);
  130. scanf("%s",mstr);
  131. N = ;
  132. init();
  133. int now = ;
  134. for(int i = ; mstr[i]; i ++){
  135. if(mstr[i] == 'B'){
  136. now = fa[now];
  137. }else if(mstr[i] == 'P'){
  138. Index[++N] = now;
  139. }else{
  140. if(nxt[now][mstr[i] - 'a'] == -){
  141. nxt[now][mstr[i] - 'a'] = newnode(now);
  142. }
  143. now = nxt[now][mstr[i] - 'a'];
  144.  
  145. }
  146. }
  147. Build();
  148. dfs(root,-);
  149. Sca(M);
  150. for(int i = ; i <= M ; i ++){
  151. query[i].x = read();
  152. query[i].y = read();
  153. query[i].id = i;
  154. }
  155. sort(query + ,query + + M,cmp);
  156. now = root;
  157. int cnt = ;
  158. int si = ;
  159. for(int i = ; mstr[i] && cnt <= M; i ++){
  160. if(mstr[i] == 'P'){
  161. si++;
  162. while(cnt <= M && query[cnt].y == si){
  163. ans[query[cnt].id] = getsum(pos[Index[query[cnt].x]].se) - getsum(pos[Index[query[cnt].x]].fi - );
  164. cnt++;
  165. }
  166. }else if(mstr[i] == 'B'){
  167. tadd(pos[now].fi,-);
  168. now = fa[now];
  169. }else{
  170. now = nxt[now][mstr[i] - 'a'];
  171. tadd(pos[now].fi,);
  172. }
  173. }
  174. for(int i = ; i <= M ; i ++){
  175. Pri(ans[i]);
  176. }
  177. return ;
  178. }

bzoj2434 fail树 + dfs序 + 树状数组的更多相关文章

  1. 2018.10.20 NOIP模拟 巧克力(trie树+dfs序+树状数组)

    传送门 好题啊. 考虑前面的32分,直接维护后缀trietrietrie树就行了. 如果#号不在字符串首? 只需要维护第一个#前面的字符串和最后一个#后面的字符串. 分开用两棵trie树并且维护第一棵 ...

  2. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2022  Solved: 1158[Submit][Sta ...

  3. 【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组

    E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  4. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

  5. 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  6. BZOJ_3881_[Coci2015]Divljak_AC自动机+dfs序+树状数组

    BZOJ_3881_[Coci2015]Divljak_AC自动机+dfs序+树状数组 Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是 ...

  7. NOI 2011 阿狸的打字机 (AC自动机+dfs序+树状数组)

    题目大意:略(太长了不好描述) 良心LOJ传送门 先对所有被打印的字符串建一颗Trie树 观察数据范围,并不能每次打印都从头到尾暴力建树,而是每遍历到一个字符就在Trie上插入这个字符,然后记录每次打 ...

  8. HDU 3887:Counting Offspring(DFS序+树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=3887 题意:给出一个有根树,问对于每一个节点它的子树中有多少个节点的值是小于它的. 思路:这题和那道苹果树是一样 ...

  9. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

随机推荐

  1. 4.namespace

    命名空间( namespace)是 Linux 内核的一个强大特性,为容器虚拟化的实现带来极大便 利. 利用这一特性,每个容器都可以拥有自己单独的命名空间,运行在其中的应用都像是在 独立的操作系统环境 ...

  2. HDU 1074 Doing Homework(经典状压dp)

    题目链接  Doing Homework        Ignatius has just come back school from the 30th ACM/ICPC. Now he has a ...

  3. Linux下git的使用——将已有项目放到github上

    本地已经有一个项目了,需要将该项目放到github上,怎么操作? 步骤: 本地安装git,有github账号是前提. (1)先在github创建一个空的仓库,并复制链接地址.使用https,以.git ...

  4. 洛谷P1897电梯里的爱情题解

    题目 这个题是一个搜索题,可以先算出最高楼层,并算出不重复的楼层的个数,要注意的一点就是一定不要把0楼算在内. 代码 #include<iostream> #include<cstr ...

  5. PHP获取网络图片并保存在本地目录

    PHP获取网络图片并保存在本地目录思路: 代码如下: function file_exists_S3($url) { $state = @file_get_contents($url,0,null,0 ...

  6. mac 使用指南

    资料检索: Command + Option + Esc 查看进程或关闭 深度开源为OPEN other 工具使用: Alfred快捷键:option+space iTerm2命令行工具 SSH Sh ...

  7. WC2019 tree

    WC2019唯一一道正常的题,考场上没什么想法,也只拿到了暴力分.搞了一天终于做完了. 前置知识:purfer序,多项式exp或分治FTT. 对于\(type=0\)的,随便维护下,算下联通块即可. ...

  8. Hdoj 1203.I NEED A OFFER! 题解

    Problem Description Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了.要申请国外的任何大学,你都要交纳一定的申请费用 ...

  9. Leetcode 75.颜色分类 By Python

    给定一个包含红色.白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色.白色.蓝色顺序排列. 此题中,我们使用整数 0. 1 和 2 分别表示红色.白色和蓝色. ...

  10. Python3 与 C# 并发编程之~ 线程篇

      2.线程篇¶ 在线预览:https://github.lesschina.com/python/base/concurrency/3.并发编程-线程篇.html 示例代码:https://gith ...