CodeForces 547E Mike and Friends AC自动机 主席树
题意:
给出\(n\)个字符串\(s_i\)和\(q\)个询问:
- \(l,r,k\):\(\sum\limits_{i=l}^{r}count(i, k)\),其中\(count(i,j)\)表示\(s_j\)作为子串在\(s_i\)中出现的次数
分析:
先不考虑查询中\(l,r\)的限制,考虑该字符串\(s_k\)在一个字符串集合中出现的次数。
先将这个字符串集合插入到一棵Trie数中,并且每经过一个节点就将其对应的\(val\)值加\(1\)。
这样\(s_k\)对应节点的\(val\)值就是以\(s_k\)为前缀的字符串的个数。
然而这还不够,接着构造出一棵fail树,也就是AC自动机中的fail指针构成的树。
这棵fail树中,父节点是子节点的后缀。
因为fail树中\(s_k\)是其子节点的后缀,所以再加上子树节点的\(val\)值。
这样就把问题转化为了求子树节点的权值之和:
利用DFS序将子树转为区间,然后用线段树维护区间和
然后考虑上题中的\(l,r\),可以将线段树可持久化或者离线查询加树状数组维护,而且离线应该是很快的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
#define PB push_back
#define PII pair<int, int>
#define REP(i, a, b) for(int i = a; i < b; i++)
#define PER(i, a, b) for(int i = b - 1; i >= a; i--)
#define ALL(x) x.begin(), x.end()
const int maxn = 200000 + 10;
const int nlogn = maxn * 40;
//persistant segment tree
int lch[nlogn], rch[nlogn], sum[nlogn];
int tot, root[maxn], p[maxn];
void update(int& rt, int pre, int L, int R, int p, int v = 1) {
rt = ++tot;
if(L == R) { sum[rt] = sum[pre] + v; return; }
int M = (L + R) / 2;
if(p <= M) { rch[rt] = rch[pre]; update(lch[rt], lch[pre], L, M, p, v); }
else { lch[rt] = lch[pre]; update(rch[rt], rch[pre], M+1, R, p, v); }
sum[rt] = sum[lch[rt]] + sum[rch[rt]];
}
int qL, qR;
int query(int rt, int pre, int L, int R) {
int ans = 0;
if(qL <= L && R <= qR) return sum[rt] - sum[pre];
int M = (L + R) / 2;
if(qL <= M) ans += query(lch[rt], lch[pre], L, M);
if(qR > M) ans += query(rch[rt], rch[pre], M+1, R);
return ans;
}
//fail tree
vector<int> G[maxn];
int l[maxn], r[maxn], dfs_clock;
void dfs(int u) {
l[u] = ++dfs_clock;
for(int v : G[u]) dfs(v);
r[u] = dfs_clock;
}
//Trie
int sz;
int ch[maxn][26], f[maxn], pos[maxn], fa[maxn];
void insert(int id, char* s) {
int u = 0;
for(int i = 0; s[i]; i++) {
int c = s[i] - 'a';
if(!ch[u][c]) {
ch[u][c] = ++sz;
memset(ch[sz], 0, sizeof(ch[0]));
}
fa[ch[u][c]] = u;
u = ch[u][c];
}
pos[id] = u;
}
void getFail() {
queue<int> Q;
REP(c, 0, 26) if(ch[0][c]) {
Q.push(ch[0][c]);
G[0].PB(ch[0][c]);
}
while(!Q.empty()) {
int r = Q.front(); Q.pop();
REP(c, 0, 26) {
int u = ch[r][c];
if(!u) ch[r][c] = ch[f[r]][c];
else {
f[u] = ch[f[r]][c];
G[f[u]].PB(u);
Q.push(u);
}
}
}
}
int n, q;
char s[maxn];
int main() {
scanf("%d%d", &n, &q);
REP(i, 0, n) {
scanf("%s", s);
insert(i + 1, s);
}
getFail();
dfs(0);
int cur = 0, s;
REP(i, 1, n + 1) {
for(int j = pos[i]; j; j = fa[j]) {
cur++;
update(root[cur], root[cur-1], 1, dfs_clock, l[j]);
}
p[i] = root[cur];
}
while(q--) {
int x, y, k; scanf("%d%d%d", &x, &y, &k);
qL = l[pos[k]], qR = r[pos[k]];
printf("%d\n", query(p[y], p[x-1], 1, dfs_clock));
}
return 0;
}
CodeForces 547E Mike and Friends AC自动机 主席树的更多相关文章
- NOI 2011 阿狸的打字机(AC自动机+主席树)
题意 https://loj.ac/problem/2444 思路 多串匹配,考虑 \(\text{AC}\) 自动机.模拟打字的过程,先建出一棵 \(\text{Trie}\) 树,把它变成自动机 ...
- codeforces 547E Mike and Friends
codeforces 547E Mike and Friends 题意 题解 代码 #include<bits/stdc++.h> using namespace std; #define ...
- hdu 4117 GRE Words (ac自动机 线段树 dp)
参考:http://blog.csdn.net/no__stop/article/details/12287843 此题利用了ac自动机fail树的性质,fail指针建立为树,表示父节点是孩子节点的后 ...
- hdu 4117 -- GRE Words (AC自动机+线段树)
题目链接 problem Recently George is preparing for the Graduate Record Examinations (GRE for short). Obvi ...
- 【BZOJ2434】阿狸的打字机(AC自动机,树状数组)
[BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...
- 【BZOJ2434】【NOI2011】阿狸的打字机(AC自动机,树状数组)
[BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...
- Codeforces 547E - Mike and Friends(AC 自动机+树状数组)
题面传送门 好久每做过 AC 自动机的题了--做几个题回忆一下罢 AC 自动机能够解决多串匹配问题,注意是匹配,碰到前后缀的问题那多半不在 AC 自动机能解决的范围内. 在初学 AC 自动机的时候相信 ...
- Codeforces 86C Genetic engineering(AC自动机+DP)
题目大概是给几个DNA片段,求构造一个长度n的字符串的方案数,要求这个字符串每个位置的字符都属于某个包含于此字符串的DNA片段. 把那些DNA片段建一个AC自动机.考虑状态的表示: dp[len][x ...
- Codeforces 291 E Tree-String Problem AC自动机
Tree-String Problem 网上的dfs + kmp 复杂度就是错的, 除非算出根据下一个字符直接转移Next数组直接转移, 而求出Next[ i ][ 26 ]数组和丢进AC自动机里面没 ...
随机推荐
- 夜色的 cocos2d-x 开发笔记 04
本章会把游戏的基本功能结束,前面实现了子弹发射,产生敌人. 接下来我们要,检测子弹与敌人碰撞,让玩家移动,实现这个游戏的基本功能. 于是多出了这几个方法,当然还是写在.h文件里 首先实现触摸监听的方法 ...
- XCode 如何真机运行别人的demo项目
iOS应用安装到真机需要证书和mobileprovision 文件,拿到别人的项目 是没有这些的 ,也就运行不起来. 要想运行起来, 需要选中项目, target - > 修改 bundlei ...
- 进一步了解this和super
知乎上看到一问题很好,拿了与大家分享,原地址:https://www.zhihu.com/question/31548104. 问: JAVA 中this 和super与覆写冲突的问题? 实例一: 输 ...
- React 环境搭建及页面调试方法
React 环境搭建及页面调试方法 |作者:RexFang |出处:http://www.cnblogs.com/rexfang/ |关于作者:Java 程序员一枚 |版权:本文版权归作者和博客园共有 ...
- AttributeError: module 'requests' has no attribute 'get' 遇到了这个错误,是因为我把python关键字做了包名。。。
初学者总会犯各种低级错误,这是其一,特此记录.
- HDU 4871 Shortest-path tree
先用dijkstra把最短路树建出来,然后就是树的质心分治了. 经过k个点的路径,要么全在子树上,要么经过根结点,因此可以分治. 如果分治的时候选点不好会变成O(n^2),比较极端的情况是比如树是一条 ...
- POJ-1990 MooFest---两个树状数组
题目链接: https://vjudge.net/problem/POJ-1990 题目大意: 一群牛参加完牛的节日后都有了不同程度的耳聋,第i头牛听见别人的讲话,别人的音量必须大于v[i],当两头牛 ...
- 高精度水题(POJ2109)
题目链接:http://poj.org/problem?id=2109 double 可以虽然可以表示10^-307~~~10^208,但是精确度只有16位,这个题有bug. #include < ...
- 模拟停车POJ(3505)
题目链接:http://poj.org/problem?id=3505 解题报告: #include <stdio.h> #include <iostream> #includ ...
- cgi程序报 Premature end of script headers:
这段时间写了一个CGI,也是为了应付工作,挺简单的一个程序,总是在调用的时候报:Premature end of script headers: 很让人头疼! 在网上找了些资料,按资料 ---- ...