题意:以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. 校园电商项目(1) 基于SSM

    第一步:搭好环境 我这里使用Eclipse做本次的项目,tomcat.maven啥的怎么弄就跳过了ヾ(o・ω・)ノ 第二步:创建工程 我们首先创建一个maven项目,选择最后一个,创建完之后发现报错, ...

  2. hive子查询

    如果集合中含有空值,不能使用not in的语法指令:但是可以使用in

  3. python中的__init__和__new__的区别

    一.__init__ 方法是什么?(init前后的线是双下划线) 使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例 ...

  4. Object.defineProperties()与Proxy对象代理

    Object.defineProperties() 了不起啊..vue.js通过它实现双向绑定的 Object.defineProperties(obj,props) 方法直接在一个对象上定义新的属性 ...

  5. Python——组图Canvas控制参数

    一.参数说明 background(bg) : 背景色; foreground(fg): 前景色; borderwidth :组件边框宽度: width  : 组件宽度: height  : 高度; ...

  6. 获取网络图片并显示在picturbox上,byte[]数组转换成Image:

    private void getWebPicture_Click(object sender, EventArgs e) { WebRequest request = WebRequest.Creat ...

  7. JS--操作DOM树

    <ul id="ul1"> <li id="li1">111</li> <li id="li2"& ...

  8. [离散时间信号处理学习笔记] 9. z变换性质

    z变换描述 $x[n] \stackrel{\mathcal{Z}}{\longleftrightarrow}X(z) ,\quad ROC=R_x$ 序列$x[n]$经过z变换后得到复变函数$X(z ...

  9. Linux服务器下安装vmware虚拟机

    安装包 1.VMware 14 https://dl-sh-ctc-2.pchome.net/08/b7/VMware-Workstation-Full-14.1.3-9474260.x86_64.b ...

  10. 大学实验3指导:利用单链表实现A-B

    实验目的:深入理解单链表的建立及操作 实验内容: 1.建立单链表A与B 2.实现主要的函数,查找.插入.删除等 3.实现操作A-B 步骤1:包含必要的函数库,对结构体LNode中的抽象数据类型Elem ...