题意:以trie的形式给出n个字符串,每次询问第x个字符串在第y个字符串中出现了几次。

解:总串长是n2级别的,所以不能用什么后缀自动机...

[update]可以建triesam但是不知道trie上的一个节点对应到了sam上的哪几个节点...感觉可以做...好混乱

听说是个AC自动机上DP,然后怎么想状态都是n²的,然后看题解发现跟DP没啥关系...

是这样的:对于x在y中出现的每一次,我们把它的前面一直补齐,这样每个串就对应着y的一个前缀,且这个前缀的一个后缀是x。

可知,trie上y节点到根的链就代表这些前缀。

然后要求后缀是x。因为x也在这些串中出现了,所以这些前缀一直跳fail的话一定会跳到x节点。即他们全都在x的fail树的子树中。

然后我们就发现,trie上y到根的路径上的节点和fail树上x的子树的节点的交就是答案。

一个很朴素的想法就是把这两棵树剖出来,就是一个二维数点问题。把主席树建出来,因为用了树剖所以每次回答询问是nlog²n的,可以做到在线。

一个高端想法就是离线下来,按照fail树建DFS序。在trie上DFS,维护trie树上当前节点到根的路径权值为1,别的地方为0。

然后查询就是当在trie上DFS到y的时候,查询x在fail树中的子树权值和。

这是单点修改,区间查询。树状数组即可。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector> const int N = ; struct Edge {
int nex, v;
}edge[N << ]; int top; struct Node {
int x, y, ans;
}node[N]; int tr[N][], fail[N], tot = ;
char str[N];
int ed[N], e[N], pos[N], siz[N], num;
std::vector<int> v[N]; namespace bit {
int ta[N];
inline void add(int p) {
for(int i = p; i < N; i += i & (-i)) {
ta[i]++;
}
return;
}
inline void del(int p) {
for(int i = p; i < N; i += i & (-i)) {
ta[i]--;
}
return;
}
inline int getSum(int p) {
int ans = ;
for(int i = p; i >= ; i -= i & (-i)) {
ans += ta[i];
}
return ans;
}
inline int ask(int l, int r) {
return getSum(r) - getSum(l - );
}
} inline void add(int x, int y) {
top++;
edge[top].v = y;
edge[top].nex = e[x];
e[x] = top;
return;
} inline void getAC() {
std::stack<int> S;
std::queue<int> Q;
int n = strlen(str), t = , p = ;
for(int i = ; i < n; i++) {
if(str[i] == 'P') {
ed[++t] = p;
continue;
}
if(str[i] == 'B') {
if(!S.empty()) {
p = S.top();
S.pop();
}
continue;
}
int f = str[i] - 'a';
if(!tr[p][f]) {
tr[p][f] = ++tot;
}
S.push(p);
p = tr[p][f];
}
// getfail
fail[] = ;
Q.push();
while(!Q.empty()) {
int x = Q.front();
Q.pop();
for(int f = ; f < ; f++) {
if(!tr[x][f]) {
continue;
}
int y = tr[x][f], j = fail[x];
while(!tr[j][f] && j != ) {
j = fail[j];
}
if(tr[j][f] && x != ) {
j = tr[j][f];
}
fail[y] = j;
add(j, y);
Q.push(y);
}
}
return;
} void DFS_1(int x) {
pos[x] = ++num;
siz[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
DFS_1(y);
siz[x] += siz[y];
}
return;
} void DFS_2(int x) {
bit::add(pos[x]);
for(int i = ; i < v[x].size(); i++) {
int t = node[v[x][i]].x;
node[v[x][i]].ans = bit::ask(pos[ed[t]], pos[ed[t]] + siz[ed[t]] - );
}
for(int i = ; i < ; i++) {
if(tr[x][i]) {
DFS_2(tr[x][i]);
}
}
bit::del(pos[x]);
return;
} int main() {
scanf("%s", str);
//
getAC();
DFS_1();
int m;
scanf("%d", &m);
for(int i = ; i <= m; i++) {
scanf("%d%d", &node[i].x, &node[i].y);
v[ed[node[i].y]].push_back(i);
} DFS_2(); for(int i = ; i <= m; i++) {
printf("%d \n", node[i].ans);
}
return ;
}

AC代码

洛谷P2414 阿狸的打字机的更多相关文章

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

    居然真的遇上了这种蔡队题.瑟瑟发抖. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿 ...

  2. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

  3. 洛谷 P2414 [NOI2011]阿狸的打字机 解题报告

    P2414 [NOI2011]阿狸的打字机 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母 ...

  4. 洛谷P2414 - [NOI2011]阿狸的打字机

    Portal Description 首先给出一个只包含小写字母和'B'.'P'的操作序列\(s_0(|s_0|\leq10^5)\).初始时我们有一个空串\(t\),依次按\(s_0\)的每一位进行 ...

  5. 【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解

        这一题是对AC自动机的充分理解和树dfs序的巧妙运用. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和' ...

  6. 洛谷P2414 [NOI2011]阿狸的打字机(AC自动机)

    传送门 考虑一下,如果串B在串A中出现过,那么A的fail指针必定直接或间接指向B 那么我们可以把fail树建起来,那么就变成B代表的节点的子树里有多少节点属于A 然后这就是一个序列统计问题,直接用d ...

  7. 洛谷 P1383 codevs 3333 高级打字机

    题目描述 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x.(t ...

  8. P2414 [NOI2011]阿狸的打字机

    P2414 [NOI2011]阿狸的打字机 AC自动机+树状数组 优质题解 <------题目分析 先AC自动机搞出Trie图 然后根据fail指针建一只新树 把树映射(拍扁)到一个序列上,用树 ...

  9. BZOJ2434: [NOI2011]阿狸的打字机(AC自动机+dfs序+树状数组)

    [NOI2011]阿狸的打字机 题目链接:https://www.luogu.org/problemnew/show/P2414 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. ...

随机推荐

  1. Farm Irrigation

    题目:Farm Irrigation 题目链接:http://210.34.193.66:8080/vj/Problem.jsp?pid=1494 题目思路:并查集 #include<stdio ...

  2. 局域网 FTP建立,搭建一个简易的局域网服务器

    1.创建用户名以及密码: 右键我的电脑 -> 管理->本地用户和组->右键用户->新用户----设置用户名密码: 2.安装IIS 和FTP :控制面板->程序->打 ...

  3. Flutter常用插件

    Dio Dio是一个强大的Dart Http请求库,支持Restful API.FormData.拦截器.请求取消等操作.视频中将全面学习和使用Dio的操作. Flutter_swiper swipe ...

  4. eclipse 编码

    单个修改 右击 选择properties  

  5. windows 10 & 禁用服务.bat

    windows 10 & 禁用服务.bat 禁用服务.bat @echo off net stop WSearch net stop wuauserv net start TrustedIns ...

  6. DButils实现数据库表下划线转bean中驼峰格式

    准备: QueryRunner queryRunner = new QueryRunner();//开启下划线->驼峰转换所用BeanProcessor bean = new GenerousB ...

  7. 包packages

    packages里面如何跨模块导入路径: print(dir()) 可以看到__file__ print(os.path.abspaht(__file__)) 可以看到当前绝对路径 import sy ...

  8. 关于读取mapper的两种方式

    第一种: 第二种:

  9. hdu-5536(字典树)

    题意:给你n个数,让你在n个数中选三个,使得(a1+a2)^a3的值最大,a1!=a2!=a3(下标不等于): 解题思路:01字典树可以写,因为数据小,我们可以先把n个数建一颗字典树,然后两边for找 ...

  10. 前端nginx+Java后台ftp处理页面图片上传踩坑

    今天,将前端代码部署到服务器nginx上,在测试多图片上传时,报错413请求体空间太大,请求都没到后台,直接被nginx拦截,调整后又报错504. 整体而言,前端存在两处问题: 413 错误 :Req ...