题目大意:略(太长了不好描述) 良心LOJ传送门

先对所有被打印的字符串建一颗Trie树

观察数据范围,并不能每次打印都从头到尾暴力建树,而是每遍历到一个字符就在Trie上插入这个字符,然后记录每次打印后字符串最后一个字符在Trie树上的位置

然后建立AC自动机,再建立Fail树。注意还要另外存一下原来Trie树的结构

Fail树就是把Fail指针倒着跑,因为每个点只有一个Fail指针,所以最后所有Fail指针会形成一棵树

Fail树有一个神奇的性质,即父节点表示的字符串(从Trie树的根节点一直到这个点所表示的字符串),一定是子节点表示的字符串的一个后缀

原问题是求x号字符串在y号字符串内出现的次数

问题可以转化为,求x作为后缀,出现在y的所有前缀的次数

根据Fail树的性质:父节点一定是子节点的后缀

那么从Trie根节点到y结尾节点的所有点,都能分别表示y的一个前缀串

而如果x是某个串的后缀,那么这个串一定在x的Fail树的子树内

如果对所有问题暴力匹配x,y又不可取

查询y的所有前缀出现在x子树内的次数,相当于在x子树内求和,貌似可以用DFS序+树状数组优化

我们可以对问题进行离线处理,把问题挂在Trie树上以y的结尾的位置上。然后跑出Fail树DFS序。再在Tire树上跑DFS,搜索到这个节点,就在它dfs序入栈的位置上+1,回溯过这个节点,就-1,这个操作其实是在表示所有可能的y的所有前缀

再回溯过这个节点之前,处理挂在这个点上所有的询问。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define idx(x) x-'a'+1
#define lowbit(x) (x&(-x))
#define N 100100
using namespace std; char str[N];
int n,m,len,num,cte,ctq,tot,dfn,qs;
int use[N],pos[N],head[N],st[N],ed[N],s[N*],hq[N];
struct Edge{int to,nxt;}edge[N*],ques[N];
void ae(int u,int v){cte++;edge[cte].to=v,edge[cte].nxt=head[u],head[u]=cte;}
void aq(int u,int v){ctq++;ques[ctq].to=v,ques[ctq].nxt=hq[u],hq[u]=ctq;}
struct AC{
int fa[N],son[N][],ch[N][],fail[N];
int cre(int w,int ff){tot++;fa[tot]=ff;return tot;}
void Build()
{
int x=;
for(int i=;i<=len;i++)
{
if('a'<=str[i]&&str[i]<='z'){
int w=idx(str[i]);
if(!ch[x][w]) ch[x][w]=son[x][w]=cre(w,x);
x=ch[x][w];
}else if(str[i]=='B'){
x=fa[x];
}else pos[++num]=x;
}
}
void Fail()
{
queue<int>q;
for(int i=;i<=;i++)
if(ch[][i]) q.push(ch[][i]),ae(,ch[][i]);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=;i<=;i++)
if(ch[x][i]){
fail[ch[x][i]]=ch[fail[x]][i];
ae(fail[ch[x][i]],ch[x][i]);
q.push(ch[x][i]);
}else{
ch[x][i]=ch[fail[x]][i];
}
}
}
void dfs(int u)
{
st[u]=++dfn;
for(int j=head[u];j;j=edge[j].nxt){
int v=edge[j].to;
dfs(v);
}ed[u]=++dfn;
}
void main()
{
Build();
Fail();
dfs();
}
}ac;
struct Ques{int x,y,id,ans;}q[N];
void update(int x,int w){for(int i=x;i<=dfn;i+=lowbit(i))s[i]+=w;}
int query(int x){int ans=;for(int i=x;i>;i-=lowbit(i))ans+=s[i];return ans;}
void dfs_ans(int x)
{
update(st[x],);
for(int i=;i<=;i++)
{
if(ac.son[x][i])
dfs_ans(ac.son[x][i]);
}
for(int j=hq[x];j;j=ques[j].nxt){
int v=ques[j].to;
q[v].ans=query(ed[pos[q[v].x]])-query(st[pos[q[v].x]]-);
}
update(ed[x],-);
} int main()
{
scanf("%s",str+);
len=strlen(str+);
ac.main();
int x,y;
scanf("%d",&m);
for(int i=;i<=m;i++)
{
scanf("%d%d",&x,&y);
qs++,q[qs].x=x,q[qs].y=y,q[qs].id=i;
aq(pos[y],qs);
}
dfs_ans();
for(int i=;i<=m;i++){printf("%d\n",q[i].ans);}
return ;
}

NOI 2011 阿狸的打字机 (AC自动机+dfs序+树状数组)的更多相关文章

  1. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

  2. BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组

    题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...

  3. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

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

  4. BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)

    题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...

  5. BZOJ_2434_[NOI2011]_阿狸的打字机_(AC自动机+dfs序+树状数组)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2434 给出\(n\)个字符串,\(m\)个询问,对于第\(i\)个询问,求第\(x_i\)个字 ...

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

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

  7. CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)

    The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...

  8. BZOJ_3881_[Coci2015]Divljak_AC自动机+dfs序+树状数组

    BZOJ_3881_[Coci2015]Divljak_AC自动机+dfs序+树状数组 Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是 ...

  9. [NOI2011][bzoj2434] 阿狸的打字机 [AC自动机+dfs序+fail树+树状数组]

    题面 传送门 正文 最暴力的 最暴力的方法:把所有询问代表的字符串跑一遍kmp然后输出 稍微优化一下:把所有询问保存起来,把模板串相同的合并,求出next然后匹配 但是这两种方法本质没有区别,都是暴力 ...

随机推荐

  1. 小程序中 wx.navigateTo 页面跳转没有反应?

    页面js文件中加入 show: function () {wx.navigateTo({url: ‘/pages/show/show’})} 这个函数 目的在于要做跳转到新的页面,但是你可能会遇到一个 ...

  2. mybatis入门截图三

    ----------------------------------------------- <!-- 用户信息的综合查询 --> <select id="userlis ...

  3. Zookeeper源代码编译为Eclipseproject(win7下Ant编译)

    为了深入学习ZooKeeper源代码,首先就想到将其导入到Eclispe中,所以要先将其编译为Eclispeproject. 1.什么是Ant??? Apache Ant™ Apache Ant is ...

  4. 【Android 应用开发】 ActionBar 样式具体解释 -- 样式 主题 简单介绍 Actionbar 的 icon logo 标题 菜单样式改动

    作者 : 万境绝尘 (octopus_truth@163.com) 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/3926916 ...

  5. Chisel Tutorial(一)——Chisel介绍

    Chisel是由伯克利大学公布的一种开源硬件构建语言,建立在Scala语言之上,是Scala特定领域语言的一个应用,具有高度參数化的生成器(highly parameterized generator ...

  6. 鸟哥Linux私房菜知识点总结3到5章

    感觉自己对Linux的理解一直不够,所以近期翻看了一本<鸟哥的Linux私房菜>.这是一本基础的书,万丈高楼平地起,会的不多但能够学.这是我整理的一些知识点,尽管非常基础.希望和大家共同交 ...

  7. EOJ 3124 单词表

    题目描述 提取英文文本中的单词,重复出现的单词只取一个,把它们按照字典顺序排序,建立为一个单词表. 例如:英文文本如下: “ask not what your country can do for y ...

  8. 杂项-公司:YKK

    ylbtech-杂项-公司:YKK YKK的全称为Yoshida Kogyo Kabushikigaisha.YKK是拉链行业的鼻祖,代表着行业标准,因为采用日本精确的工艺,原料和管理方法,YKK价格 ...

  9. UINavi中push控制器的时候隐藏TabBar

    当一个UITabbarController管理多个UINavigationController的时候,我们又从这每一个UINavigationController中push一个ViewControll ...

  10. 写函数,输入n个数字输出最大值和最小值

    # ,写函数,传入n个数,返回字典{‘max’:最大值,’min’:最小值}# 例如:min_max(2,5,7,8,4) 返回:{‘max’:8,’min’:2}(此题用到max(),min()内置 ...