传送门

AC自动机 + 树状数组

建成AC自动机后,设end[i]为第i个串的末尾在Trie树上的节点。

可以发现,对于一个询问(x,y),ans等于Trie树上root到end[y]这条链上fail指针指向end[x]的节点数,我们把这些点记为特殊点

因为Trie树上每个节点fail指针仅指向一个值,

因此可以将fail指针反转构建一棵树,以下称为fail树。

于此答案可以等价于在fail树上以end[x]为根的子树中存在的特殊点个数。

然而这样暴力做还是过不了。于是需要一些优化。

可以知道将一个树的节点按dfs序排列后,

树的任意一颗子树的节点在序列中都是连续的一段区间。

我们把特殊的点记为1,非特殊点记为0,

于是求某子树上的特殊点个数可以转化成求某区间的和,

于是就可以用树状数组来优化了。(线段树应该也可以吧,不过似乎会比较麻烦)。

代码:

 #include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring> using namespace std; #define N ((1<<17)-1)
#define M ((1<<17)-1)
#define lowbit(x) ((x)&(-(x))) queue<int>q;
char s[N];
int end[N],n; struct ACA
{
int cnt;
int fa[N],son[N][],fail[N];
void get_trie()
{
cnt=;
int i,now=,v,p=;
for (i=;i<n;i++)
switch(s[i])
{
case 'P':{end[++p]=now;break;}
case 'B':{now=fa[now];break;}
default:
{
v=s[i]-'a';
if (!son[now][v])
{
son[now][v]=++cnt;
fa[cnt]=now;
}
now=son[now][v];
}
}
for (i=;i<;i++) son[][i]=;
}
void get_fail()
{
int i,j,x;
q.push();
while (!q.empty())
{
x=q.front(),q.pop();
for (i=;i<;i++)
if (son[x][i])
{
for (j=fail[x];j&&!son[j][i];j=fail[j]);
fail[son[x][i]]=son[j][i];
q.push(son[x][i]);
}
}
}
}aca; struct BIT
{
int arr[N],l[N],r[N];
int sum(int i)
{
int re=;
while (i)
{re+=arr[i];i-=lowbit(i);}
return re;
}
void add(int i,int k)
{
while (i<=aca.cnt)
{arr[i]+=k;i+=lowbit(i);}
}
}bit; struct Tree
{
vector<vector<int> >son;
void addedge(int u,int v)
{
son[u].push_back(v);
}
void build()
{
son.resize(aca.cnt+);
for (int i=;i<=aca.cnt;i++)
addedge(aca.fail[i],i);
}
void dfs_order(int x,int &k)
{
bit.l[x]=bit.r[x]=k++;
for (int i=;i<son[x].size();i++)
{
dfs_order(son[x][i],k);
bit.r[x]=max(bit.r[x],bit.r[son[x][i]]);
}
}
}tree; int x[M],ans[M],pre[N],now[N]; inline int val(int x)
{
return bit.sum(bit.r[x])-bit.sum(bit.l[x]-);
} void answer()
{
int m,i,j,y,v,p;
scanf("%d",&m);
memset(now,,sizeof(now));
for (i=;i<=m;i++)
{
scanf("%d%d",&x[i],&y);
x[i]=end[x[i]];
y=end[y];
pre[i]=now[y];
now[y]=i;
}
for (p=,i=;i<n;i++)
{
switch(s[i])
{
case 'P':
{
for (j=now[p];j;j=pre[j])
ans[j]=val(x[j]);
break;
}
case 'B':
{
bit.add(bit.l[p],-);
p=aca.fa[p];
break;
}
default:
{
v=s[i]-'a';
p=aca.son[p][v];
bit.add(bit.l[p],);
}
}
}
for (i=;i<=m;i++)
printf("%d\n",ans[i]);
} int main()
{
scanf("%s",s);
n=strlen(s);
aca.get_trie();
aca.get_fail();
tree.build();
int k=;
tree.dfs_order(,k);
answer();
}

[NOI 2011][BZOJ 2434] 阿狸的打字机的更多相关文章

  1. AC自动机:BZOJ 2434 阿狸的打字机

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1834  Solved: 1053[Submit][Sta ...

  2. bzoj 2434 阿狸的打字机 - Aho-Corasick自动机 - 树状数组

    题目传送门 传送站I 传送站II 题目大意 阿狸有一个打字机,它有3种键: 向缓冲区追加小写字母 P:打印当前缓冲区(缓冲区不变) B:删除缓冲区中最后一个字符 然后多次询问第$x$个被打印出来的串在 ...

  3. BZOJ 2434 阿狸的打字机(fail树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2434 题意:阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28 ...

  4. BZOJ 2434 阿狸的打字机

    http://www.lydsy.com/JudgeOnline/problem.php?id=2434 思路:建立fail树,并找出dfs序,那剩下要做的就是每次找到一个串的位置,然后询问它的区间里 ...

  5. bzoj 2434: 阿狸的打字机 fail树+离线树状数组

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 首先我们可以发现这个打字的过程本身就是在Trie上滚来滚去的过程 所以我们 ...

  6. bzoj 2434 阿狸的打字机 fail树的性质

    如果a串是另b串的后缀,那么在trie图上沿着b的fail指针走一定可以走到a串. 而a串在b串里出现多少次就是它是多少个前缀的后缀. 所以把fail边反向建树维护个dfs序就行了. 并不是很难... ...

  7. BZOJ 2434 阿狸的打字机 | AC自动机

    题目戳这里 AC自动机上有神奇的东西叫做fail指针--所有fail指针连起来恰好构成一棵以1为根的树! 而这道题问x在y中出现过多少次,就是问Trie树上根到y的结束节点的路径上有多少节点能通过跳f ...

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

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

  9. 【BZOJ】【2434】【NOI2011】阿狸的打字机

    AC自动机+DFS序+BIT 好题啊……orz PoPoQQQ 大爷 一道相似的题目:[BZOJ][3172][TJOI2013]单词 那道题也是在fail树上数有多少个点,只不过这题是在x的fail ...

随机推荐

  1. PHP 练习3:租房子

    一.题目要求 二.题目做法 1.建立数据库 2.封装类文件 <?php class DBDA { public $fuwuqi="localhost"; //服务器地址 pu ...

  2. 基本控件文档-UISegment属性----iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ...

  3. 【网络爬虫入门01】应用Requests和BeautifulSoup联手打造的第一条网络爬虫

    [网络爬虫入门01]应用Requests和BeautifulSoup联手打造的第一条网络爬虫 广东职业技术学院 欧浩源 2017-10-14  1.引言 在数据量爆发式增长的大数据时代,网络与用户的沟 ...

  4. node.js 开发命令行工具 发布npm包

    新建一个文件夹“nodecmd”: 在nodecmd下新建文件夹bin: 在bin文件夹下新建JavaScript文件hello.js #!/usr/bin/env node console.log( ...

  5. Perl6 Bailador框架(6):获取用户输入

    use v6; use Bailador; get '/' => sub { ' <html> <head><title></title>< ...

  6. Linux_信号与信号量【转】

    转自:http://blog.csdn.net/sty23122555/article/details/51470949 信号: 信号机制是类UNIX系统中的一种重要的进程间通信手段之一.我们经常使用 ...

  7. 2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6153 A Secret KMP,思维

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6153 题意:给了串s和t,要求每个t的后缀在在s中的出现次数,然后每个次数乘上对应长度求和. 解法:关 ...

  8. iOS 适配/ autoLayout基本知识

    历史 iPhone3GS.iPhone4\4s:没有屏幕适配最早开发里面的程序全部都是写死的 iPad 旋转出来之后 Autoresizing问世iPhone5\5c\5s兼容各种不同的情况 系统适配 ...

  9. linux命令(12):ping命令

    1.ping网关:ping –b 192.168.1.1 2.ping指定次数:ping -c 10 192.168.1.100 3.时间间隔和次数限制的ping:ping -c 10 -i 0.5 ...

  10. linux命令(8):du命令

    du –ah:查看文件列表大小 du –sh:查看所有文件的大小总和