洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)
要点
- 这是一道蔡队题,看我标题行事
- 任意询问y串上有多少个x串,暴力找每个节点是不是结尾肯定是炸的,考虑本质:如果某节点是x的结尾,根据ac自动机的性质,x一定是此(子)串后缀。又有每个Trie节点的fail只指向另一个节点,故有fail树的概念。问题就变成了“对于串x的尾节点,在fail树中它的子树中有多少个点是在y串上”。
- 解决方法是巧妙的。
- 离线记录查询的信息。然后搜索原Trie树,遇到尾节点就扫描它有哪些查询,这里尾节点是y的尾节点。而当前搜索时如果我们在搜该点,则该点计数++,搜完它的子树回溯了,该点计数--,这样做使得搜到尾节点时,只有这个字符串上的节点才有计数,达到了想要的效果:只有串y的节点才有计数。
- 那么现在y上的所有节点都被计数了,怎样统计有多少个是在x的fail子树上呢?就是在之前预处理dfs序,子树的常规操作。这样计数是在dfn上进行的,维护和查询用一下树状数组即可,想查询x的子树有多少值就直接查询前缀和即可。
- 注意除了思路以外还有写法上的优化,就题论板子,比如这题常规地insert就会T,发现题目特殊性质可以特殊插入,大大加快了速度。
- 总的来讲虽然标题很花哨但是操作都是中规中矩的,需要什么映射的数组就开一下就是了。其实没处理鲁棒性使得一些数据能hack掉我的代码,比如空串还删或者出现相同的串,但没想到A了那就懒得改了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string>
#include <queue>
#include <vector>
#include <map>
using namespace std;
const int N = 1e5 + 5;
char op[N], t[N];
int m, cnt;
vector<pair<int, int>> query[N];
int trie[N][26], dfn[N], size[N], Time;
int x, y, ans[N];
int ch[N][26];//Trie树的转移
int fa[N];
int val[N];//根据题意赋值。有值则意味着某子串末尾
int fail[N];//失配,转移到别的树枝接着找
int sz;//注意这个板子sz一定是要从1开计
int book[N];
vector<int> ftr[N];
void getfail() {
queue<int> Q;
for (int i = 0; i < 26; i++)
if (ch[0][i]) {
fail[ch[0][i]] = 0;
ftr[0].push_back(ch[0][i]);
Q.push(ch[0][i]);//第二层指向根
}
while (!Q.empty()){
int u = Q.front(); Q.pop();
for (int i = 0; i < 26; i++)
if (ch[u][i]){
fail[ch[u][i]] = ch[fail[u]][i];
if (val[ch[u][i]] != -1)
ftr[ch[fail[u]][i]].push_back(ch[u][i]);
Q.push(ch[u][i]);//指向其他枝上同样的字母
} else ch[u][i] = ch[fail[u]][i];//使得find时半路突然失配时还能一下拐回去
}
}
void dfs(int now) {
dfn[now] = ++Time;
size[now] = 1;
for (int i : ftr[now]) {
dfs(i);
size[now] += size[i];
}
}
struct BIT {
int F[N];
void add(int x, int val) {
for (; x <= Time; x += x&-x)
F[x] += val;
}
int ask(int x) {
int res = 0;
for (; x; x -= x&-x)
res += F[x];
return res;
}
}bit;
void Dfs(int cur) {
int y = val[cur];
bit.add(dfn[cur], 1);
if (y != -1) {
for (auto i : query[y]) {
int sz = book[i.first];
ans[i.second] = bit.ask(dfn[sz] + size[sz] - 1) - bit.ask(dfn[sz] - 1);
}
}
for (int i = 0; i < 26; i++) {
if (trie[cur][i])
Dfs(trie[cur][i]);
}
bit.add(dfn[cur], -1);
}
int main() {
memset(val, -1, sizeof val);
scanf("%s", op);
int L = strlen(op), now = 0;
for (int i = 0; i < L; i++) {
if (op[i] == 'B') {
now = fa[now];
} else if (op[i] == 'P') {
val[now] = ++cnt;
book[cnt] = now;
} else {
if (!ch[now][op[i] - 'a']) {
trie[now][op[i] - 'a'] = ch[now][op[i] - 'a'] = ++sz;
val[sz] = 0;
fa[sz] = now;
}
now = ch[now][op[i] - 'a'];
}
}
getfail();
dfs(0);
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
scanf("%d %d", &x, &y);
query[y].push_back({x, i});
}
Dfs(0);
for (int i = 1; i <= m; i++) {
printf("%d\n", ans[i]);
}
}
洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)的更多相关文章
- AC自动机fail树上dfs序建线段树+动态memset清空
题意:http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路:https://blog.csdn.net/u013306830/article/detail ...
- 洛谷P3808 & P3796 AC自动机模板
题目:P3808:https://www.luogu.org/problemnew/show/P3808 P3796:https://www.luogu.org/problemnew/show/P37 ...
- 洛谷 - P3966 - 单词 - AC自动机
https://www.luogu.org/problemnew/show/P3966 因为文本串就是字典本身,所以这个和平时的AC自动机不太一样.平时的query要沿着fail树把子树的出现次数依次 ...
- CodeForces - 1207G :Indie Album(AC自动机 fail树上DFS)
题意:有N个串,给出的形式是拼接给出,对于第i行: (1,c)表示字符串i是单个字母c: (2,p,c)表示字符串i=在字符串p后面接上一个字母c. 然后给出M个提问,形式是(i,string).问 ...
- 洛谷.3121.审查(AC自动机 链表)
题目链接 //删掉一个单词需要前移一段位置,用链表维护就好了 复杂度O(sum(len)) #include <cstdio> #include <cstring> #defi ...
- 洛谷 - P2444 - 病毒 - AC自动机
https://www.luogu.org/problemnew/show/P2444 有点恶心,不太明白fail的意义. #include<bits/stdc++.h> using na ...
- 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)
被\(STL\)坑害了一个晚上,真的菜的没救了啊. 准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\) 有一个非常重要的性质 在反向迭代器中,+ ...
- BZOJ 3551/3545: [ONTAK2010]Peaks加强版 (Kruskal树+dfs序上的主席树+倍增)
Orz PoPoQQQ 学到了维护子树信息的时候用dfsdfsdfs序套主席树节省线段树空间. 学到了怎么用指针写可持久化线段树-emmm- CODE 只贴上3551加强版带强制在线的代码 #incl ...
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 3610 Solved: 1960 [Submit][S ...
随机推荐
- pycharm解决Inconsistent indentation:mix of tabs and spaces
- NASNet学习笔记—— 核心一:延续NAS论文的核心机制使得能够自动产生网络结构; 核心二:采用resnet和Inception重复使用block结构思想; 核心三:利用迁移学习将生成的网络迁移到大数据集上提出一个new search space。
from:https://blog.csdn.net/xjz18298268521/article/details/79079008 NASNet总结 论文:<Learning Transfer ...
- cifs挂载远程文件出现 No such device or address错误
1. 参考 https://www.raspberrypi.org/forums/viewtopic.php?t=82199 找了两天看到这个文章才解决了问题. 我是之前同事在windows上挂载成功 ...
- Promise 入门与使用
Tags: ECMAScript6 参考资料 promises-book Promise对象 we-have-a-problem-with-promises Promise最初被提出是在 E语言中, ...
- COM组件宏观认识
一直搞不清楚COM到底是个什么东西,记录一些个人感想,可能很多错误的,慢慢消化. 一.宏观认识: 1.COM(组件对象模型)是一种标准,规则,要求,即即于建筑设计指标要求. 2.语言无关性,因为是建立 ...
- Gym:101630J - Journey from Petersburg to Moscow(最短路)
题意:求1到N的最短路,最短路的定义为路径上最大的K条边. 思路:对于每种边权,假设为X,它是第K大,那么小于X的变为0,大于K的,边权-X.然后求最短路,用dis[N]+K*X更新答案. 而小于K的 ...
- HAOI2006受欢迎的牛——缩点
题目:http://poj.org/problem?id=2186 本题是缩点模板题,将强连通分量缩成一个点,从而形成一个有向无环图,当仅有一个出度为0的点时答案即此点的大小,否则无解. 代码如下: ...
- SQL Server 将查询的结果生成insert语句
1.将查询的结果插入到一张新表(yangTest 表系统会自动生成)select Area, District, RoadName, StationName, PathDirection, Stati ...
- 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)
No valid host was found. There are not enough hosts available 'ascii' codec can't decode byte 0xe6 i ...
- FZU 2059 MM (并查集+排序插入)
Problem 2059 MM Accept: 109 Submit: 484Time Limit: 1000 mSec Memory Limit : 32768 KB Problem ...