【[NOI2011]阿狸的打字机】
首先发现这个插入的非常有特点,我们可以直接利用这个特殊的性质在\(Trie\)树上模拟指针的进退
之后得到了\(Trie\)树,先无脑建出\(AC\)机
之后考虑一下如何写暴力
最简单的暴力对于每一个询问直接在\(AC\)机上匹配之后跳\(fail\),跳到多少次\(fail\)就代表出现了几次
显然这并不能通过
考虑一下优雅的跳\(fail\)
发现\(fail\)指针建出来恰好是一个树的结构,因为一个点的\(fail\)只能指向唯一的一个点
把这样一棵\(fail\)树建出来,我们直接在\(fail\)树上判断另一个串的结束标记是否在这个点到根的路径上就好了
可以对\(fail\)树搞一个\(dfs\)序,之后把问题转化为单点加,区间查显然可以直接用一个树状数组来维护
但是这个样子还是要对每一个串都进行一遍这样的操作
但是考虑到每一个查询操作有很多共用的节点,我们可以直接按照\(Trie\)上的顺序离线下来,之后利用大量重复的这一特性去统计答案
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define re register
#define maxn 100005
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define lowbit(x) ((x)&(-x))
struct E
{
int v,nxt;
}e[maxn<<1];
int head[maxn],fa[maxn];
int n,m,to[maxn],dfn[maxn],DFN[maxn];
int cnt,num,tot,__,t;
struct Ask
{
int x,y,rk,ans;
}a[maxn];
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
inline void add_edge(int x,int y)
{
e[++num].v=y;
e[num].nxt=head[x];
head[x]=num;
}
char S[maxn];
int c[maxn],sum[maxn];
inline void add(int x,int val){for(re int i=x;i<=cnt+1;i+=lowbit(i)) c[i]+=val;}
inline int ask(int x){int now=0;for(re int i=x;i;i-=lowbit(i)) now+=c[i];return now;}
int son[maxn][26],trie[maxn][26],fail[maxn],Ans[maxn];
inline void ins()
{
int now=0;
fa[now]=0;
scanf("%s",S+1);
int len=strlen(S+1);
for(re int i=1;i<=len;i++)
{
if(S[i]=='B')
{
now=fa[now];
continue;
}
if(S[i]=='P')
{
to[++tot]=now;
continue;
}
if(!son[now][S[i]-'a']) son[now][S[i]-'a']=trie[now][S[i]-'a']=++cnt,fa[cnt]=now;
now=son[now][S[i]-'a'];
}
}
inline void Build()
{
std::queue<int> q;
for(re int i=0;i<26;i++) if(son[0][i]) q.push(son[0][i]);
while(!q.empty())
{
int k=q.front();q.pop();
for(re int i=0;i<26;i++)
if(son[k][i]) fail[son[k][i]]=son[fail[k]][i],q.push(son[k][i]);
else son[k][i]=son[fail[k]][i];
}
}
inline int cmp(Ask A,Ask B)
{
return dfn[A.x]<dfn[B.x];
}
void DFS(int x)
{
dfn[x]=++__;
if(x!=fail[x]) add_edge(fail[x],x);//printf("%d\n",x);
for(re int i=0;i<26;i++)
if(trie[x][i]) DFS(trie[x][i]);
}
void dfs(int x,int F)
{
sum[x]=1;DFN[x]=++__;
for(re int i=head[x];i;i=e[i].nxt)
if(e[i].v!=F)
{
dfs(e[i].v,x);
sum[x]+=sum[e[i].v];
}
}
void Dfs(int x)
{
__++;
add(DFN[x],1);
while(a[t].x==x)
{
int Y=to[a[t].y];
a[t].ans=ask(DFN[Y]+sum[Y]-1)-ask(DFN[Y]-1);
t++;
}
for(re int i=0;i<26;i++)
if(trie[x][i]) Dfs(trie[x][i]);
add(DFN[x],-1);
}
int main()
{
ins();
Build(),DFS(0);
n=read();
for(re int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),a[i].rk=i,std::swap(a[i].x,a[i].y),a[i].x=to[a[i].x];
std::sort(a+1,a+n+1,cmp);
__=0,dfs(0,0),__=0;t=1;
Dfs(0);
for(re int i=1;i<=n;i++) Ans[a[i].rk]=a[i].ans;
for(re int i=1;i<=n;i++) printf("%d\n",Ans[i]);
return 0;
}
【[NOI2011]阿狸的打字机】的更多相关文章
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...
- [NOI2011]阿狸的打字机(好题!!!!)
2785: [NOI2011]阿狸的打字机 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 7 Solved: 3[Submit][Status][We ...
- P2414 [NOI2011]阿狸的打字机
P2414 [NOI2011]阿狸的打字机 AC自动机+树状数组 优质题解 <------题目分析 先AC自动机搞出Trie图 然后根据fail指针建一只新树 把树映射(拍扁)到一个序列上,用树 ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
- [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组
[NOI2011] 阿狸的打字机 题目描述: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现, ...
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 3610 Solved: 1960 [Submit][S ...
- BZOJ2434: [NOI2011]阿狸的打字机(AC自动机+dfs序+树状数组)
[NOI2011]阿狸的打字机 题目链接:https://www.luogu.org/problemnew/show/P2414 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. ...
- bzoj 2434 [Noi2011]阿狸的打字机 AC自动机
[Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4001 Solved: 2198[Submit][Status][D ...
- 洛谷 P2414 [NOI2011]阿狸的打字机 解题报告
P2414 [NOI2011]阿狸的打字机 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母 ...
随机推荐
- Windows窗体技术及基础控件
创建winform程序 Visual studio是一套完整的开发工具集 RAD 工具(rapid application development) 创建用户界面时,把控件从工具箱拖放到窗体上,把它们 ...
- NSURLSession和NSURLConnection
iOS9.0之后NSURLConnection被注销,采用NSURLSession,先介绍NSURLSession,然后介绍NSURLConnection 1.NSURLSession: post请求 ...
- 赶集网mysql开发36军规
赶集网mysql开发36军规 写在前面的话: 总是在灾难发生后,才想起容灾的重要性: 总是在吃过亏后,才记得曾经有人提醒过. (一)核心军规 (1)不在数据库做运算:cpu计算务必移至业务层 (2)控 ...
- HDU 4489(DP)
http://acm.hdu.edu.cn/showproblem.php?pid=4489 解题思路这里已经说的很清楚了: http://blog.csdn.net/bossup/article/d ...
- jQuery bind()与delegate()的区别
笔试题: bind()与delegate()的区别主要有三点: 1 绑定目标 .bind直接绑在目标元素上 .delegate绑在父元素上 2 监听个数 .bind监听个数多——每个目标元素都需要添 ...
- Java 实时论坛 - Sym 1.4.0 发布
简介 Sym 是一个用 Java 写的实时论坛,欢迎来体验! 如果你需要搭建一个企业内网论坛,请使用 SymX. 作者 Sym 的主要作者是 Daniel 与 Vanessa,所有贡献者可以在这里看到 ...
- Java设计模式—组合模式
组合模式是一种常见的设计模式(但我感觉有点复杂)也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系. 个人理解:组合模式就是将部分组装成整体. 定义如下: 将对象组合成树形结构以表 ...
- LintCode2016年8月22日算法比赛----将数组重新排序以构造最小值
将数组重新排序以构造最小值 题目描述 给定一个整数数组,请将其重新排序,以构造最小值. 样例 给定[3,32,321],通过将数组重新排序,可构造6个可能性的数字: 3+32+321=332321 3 ...
- Hadoop & Spark & Hive & HBase
Hadoop: http://hadoop.apache.org/docs/r2.6.4/hadoop-project-dist/hadoop-common/SingleCluster.html bi ...
- java indexOf 和 split的用法
1.java 的 indexOf 方法 ,如果存在 则 指定的字符串的开始位置,如果不存在 则返回-1: 2.java 的 split的方法:将一个字符串分割为子字符串,然后将结果作为字符串数组返回. ...