洛谷P2414 阿狸的打字机
题意:以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 阿狸的打字机的更多相关文章
- 洛谷P2414 阿狸的打字机【AC自动机】【fail树】【dfs序】【树状数组】
居然真的遇上了这种蔡队题.瑟瑟发抖. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿 ...
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- 洛谷 P2414 [NOI2011]阿狸的打字机 解题报告
P2414 [NOI2011]阿狸的打字机 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母 ...
- 洛谷P2414 - [NOI2011]阿狸的打字机
Portal Description 首先给出一个只包含小写字母和'B'.'P'的操作序列\(s_0(|s_0|\leq10^5)\).初始时我们有一个空串\(t\),依次按\(s_0\)的每一位进行 ...
- 【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解
这一题是对AC自动机的充分理解和树dfs序的巧妙运用. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和' ...
- 洛谷P2414 [NOI2011]阿狸的打字机(AC自动机)
传送门 考虑一下,如果串B在串A中出现过,那么A的fail指针必定直接或间接指向B 那么我们可以把fail树建起来,那么就变成B代表的节点的子树里有多少节点属于A 然后这就是一个序列统计问题,直接用d ...
- 洛谷 P1383 codevs 3333 高级打字机
题目描述 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x.(t ...
- P2414 [NOI2011]阿狸的打字机
P2414 [NOI2011]阿狸的打字机 AC自动机+树状数组 优质题解 <------题目分析 先AC自动机搞出Trie图 然后根据fail指针建一只新树 把树映射(拍扁)到一个序列上,用树 ...
- BZOJ2434: [NOI2011]阿狸的打字机(AC自动机+dfs序+树状数组)
[NOI2011]阿狸的打字机 题目链接:https://www.luogu.org/problemnew/show/P2414 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. ...
随机推荐
- Quartz框架学习(1)—核心层次结构
Quartz框架学习 Quartz(任务调度)框架的核心组件: job:任务.即任务调度行为中所要调度的对象. trigger:触发器.是什么促使了一个任务的调度?当然是时间.这也算事件驱动类型程序. ...
- hive表链接
等值连接 不等职链接 外部链接 没有包含在聚合函数(这里是count)中的列,都需要包含在group by函数中: 正确的外链接的写法,用的是右外链接: 自链接表 把同一张表 看成了2张表
- VMware与CentOS的安装与Linux简单指令
一 . VMware与CentOS系统安装 下载CentOS系统的ISO镜像 # 官方网站,国外网站,下载速度会很慢 www.centos.org # 由于国外的下载速度慢,我们可以使用国内的镜像源 ...
- kprobe原理解析
参考 http://www.cnblogs.com/honpey/p/4575928.html kprobe是linux内核的一个重要特性,是一个轻量级的内核调试工具,同时它又是其他一些更高级的内核 ...
- fiddler 笔记-重定向
重定向功能:主要是进行会话的拦截,然后替换原始资源的功能 选择请求-到autoresponser面板-勾选 enable rules :add rules 设置如下: 2 在浏览器中请示url-页面跳 ...
- Condition线程通信(七)
前言:对于线程通信,使用synchronized时使用wait.notify和notifyAll来实行线程通信.而使用Lock如何处理线程通信呢?答案就是本片的主角:Condition. 一.Cond ...
- cuda培训素材
http://www.geforce.cn/hardware/desktop-gpus/geforce-gtx-480/architecture http://cache.baiducontent.c ...
- DeepLearning训练方法
1.BN层训练技巧 缩小输入尺寸,这样可以提高batchsize的大小,在BN层适应了该数据集后,固定住BN层参数,放大输入尺寸继续训练 2.语义分割中解决网络输出尺寸与原尺寸的gap方法(如 1/8 ...
- bzoj1861
bzoj1861[ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本 ...
- 找工作的程序员必懂的Linux
一.为什么要学习Linux 首先,我想先说一下:“为什么要学习Linux”?Linux 是什么,它是一款操作系统,是一个支持多用户.多任务.支持多线程和多CPU的操作系统:32位和64位的硬件可以在L ...