bzoj 2780
后缀自动机的应用
首先我们观察到:如果一个询问串的答案不为0,那么这个串一定是至少一个模式串的子串
如果只有一个模式串,那么这个问题可以简单地用什么东西解决掉(比如普通后缀自动机)
而这里有很多模式串,所以普通后缀自动机是不够的。
那么我们提出广义后缀自动机
所谓广义后缀自动机,可以简单理解成将很多个串建在同一个后缀自动机上
所以它的构造就是:每插入完毕一个串,就将las指针指回根节点,然后去构造下一个串就可以了
好像很简单?
上面的构造方法是不准确的!
这里转载一位dalao的博客,他详尽地给出了如上的构造方法的错误之处以及正确的方法
(但是太恶心了,而且一般错误的方法也不会被卡,所以我们这里还是使用了错误方法,但是在这里要有个印象,这并不是完全正确的构造方法)
接下来是转载部分:
"由于之前的疏忽,一直认为广义后缀自动机的构建方法就是在普通后缀自动机上直接插入多串,在此修正
原先的方法:对第一个串建后缀自动机,在插入第二个串时将fin指针指向根,然后暴力插入第二个字符串。
这种方法的错误:
当原来的字符串集合中含有这个字符串时,便会多建立新点,这个点并没有被任何点的tranc指向。
为什么之前一直没出问题:
我做题太少了
在大多数情况下,这个点是不会更新且不会被更新的,而且它前后的点都表现正常。
所以,在所有串都是静态的,就是一遍建成在大多数情况下是不会出现问题的。
那什么时候出现的问题:
当这个字符串集合是动态的(只插入不删除)时,一般我们使用LCT来维护Parent树。
这时,当我们拎出链进行修改时这个点就会参与运算,(然而这个点还没有记录原来修改的值)所以重复字符串/字符串前缀是需要在建立广义后缀自动机时进行特判处理
广义后缀自动机的本质:
普通后缀自动机是依靠字符串建立起来的。
而广义后缀自动机原则上是在原字符串集合的trie树上建立的,原则上要先建出trie树,然后记录每个点的fin指针。
每个节点在构建时需要在父亲的fin上构造。
原则上trie树的遍历可以使用dfs和bfs,但是dfs可以被构造的数据卡成O(n2)O(n2)
所以原则上要使用bfs来建广义后缀自动机。
但是考虑我们要解决的问题,也就是trie上构造和直接插入本质上的区别,就是trie树省略了前缀的重复
从这个性质入手,可以直接将后缀树的节点破开(特判一下就好了,就是前缀重复时像trie一样搞就好了)”
转载部分结束
接下来进入正题
我们还是按照老方法构造广义后缀自动机,本题不会被卡
然后我们分析一下题意:
如果一个询问串是一个模式串的子串,那么这个询问串一定是这个模式串的一个前缀的后缀(虽然我们常用的定义是后缀的前缀,但是在这个“后缀自动机”里我们使用第一个定义更容易理解)
那么,基于后缀自动机的pre指针的定义,我们发现:一个pre指针指向的点所对应的串一定是原节点对应字符串的一个后缀!
那么,如果我们将pre指针反指,就会得到一个树形结构,我们称这棵树叫parent树
我们可以发现,parent树的一个父节点对应的串是它所有子代节点(即儿子,儿子的儿子...)所对应串的子串!
以上内容,是在学习后缀自动机时应当了解到的,其实是基础知识,但是还是要介绍一下
那么对于这道题,我们发现:考虑到如果答案不为0,那么后缀自动机一定能识别这个串
所以我们可以先用建好的后缀自动机去识别每一个串,以此就可以查出所有答案为0的部分
然后,我们记录下答案不为0的询问串的结束位置,然后我们建起parent树求出dfs序,那么我们只需求出对于每个结束位置,它在parent树上的子树内有多少个不同的endpos即可(在广义后缀自动机上,用不同的endpos区分不同的串)
这一点可以利用dfs序实现
具体来讲,求出parent树的dfs之后,基于dfs序的性质,问题就转变成了在一段区间内(即询问节点的入栈序与出栈序)之间不同数值的个数
那么这类似于bzoj 1878,HH的项链
我们只需离线所有询问,然后用树状数组搞就可以了。
具体看代码
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
struct SAM
{
int tranc[27];
int endpos;
int pre;
int len;
}s[200005];
struct Edge
{
int next;
int to;
}edge[200005];
struct Ques
{
int lq,rq,num;
}q[60005];
int cnt=1;
int n,m;
char ch[360005];
int head[200005];
int inr[200005];
int our[200005];
int sum[400005];
int last[200005];
int ret[60005];
int f[400005];
int las,siz;
int dep;
int tot;
void init()
{
memset(head,-1,sizeof(head));
cnt=1;
}
bool cmp(Ques x,Ques y)
{
return x.rq<y.rq;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int l,int r)
{
edge[cnt].next=head[l];
edge[cnt].to=r;
head[l]=cnt++;
}
void update(int x,int y)
{
while(x<=dep)
{
sum[x]+=y;
x+=lowbit(x);
}
}
int get_sum(int x)
{
int ans=0;
while(x)
{
ans+=sum[x];
x-=lowbit(x);
}
return ans;
}
void ins(int c,int typ)
{
int nwp=++siz;
s[nwp].endpos=typ;
s[nwp].len=s[las].len+1;
int lsp;
for(lsp=las;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)s[lsp].tranc[c]=nwp;
if(!lsp)
{
s[nwp].pre=1;
}else
{
int lsq=s[lsp].tranc[c];
if(s[lsq].len==s[lsp].len+1)
{
s[nwp].pre=lsq;
}else
{
int nwq=++siz;
s[nwq]=s[lsq];
s[nwq].len=s[lsp].len+1;
s[nwq].endpos=0;
s[lsq].pre=s[nwp].pre=nwq;
while(s[lsp].tranc[c]==lsq)s[lsp].tranc[c]=nwq,lsp=s[lsp].pre;
}
}
las=nwp;
}
void buildtree()
{
init();
for(int i=2;i<=siz;i++)add(s[i].pre,i);
}
void dfs(int x)
{
inr[x]=++dep;
f[dep]=x;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
dfs(to);
}
our[x]=++dep;
}
int check(int l)
{
int laas=1;
for(int i=1;i<=l;i++)
{
if(s[laas].tranc[ch[i]-'a'+1])laas=s[laas].tranc[ch[i]-'a'+1];
else return 0;
}
return laas;
}
int main()
{
scanf("%d%d",&n,&m);
las=++siz;
for(int i=1;i<=n;i++)
{
scanf("%s",ch+1);
int len=strlen(ch+1);
for(int j=1;j<=len;j++)ins(ch[j]-'a'+1,i);
las=1;
}
buildtree();
dfs(1);
for(int i=1;i<=m;i++)
{
scanf("%s",ch+1);
int len=strlen(ch+1);
int t=check(len);
if(t)
{
q[++tot].lq=inr[t];
q[tot].rq=our[t];
q[tot].num=i;
}
}
sort(q+1,q+tot+1,cmp);
int ttop=1;
for(int i=1;i<=dep;i++)
{
update(i,1);
if(last[s[f[i]].endpos])update(last[s[f[i]].endpos],-1);
last[s[f[i]].endpos]=i;
while(q[ttop].rq==i)
{
ret[q[ttop].num]=get_sum(q[ttop].rq)-get_sum(q[ttop].lq-1)-1;
ttop++;
}
}
for(int i=1;i<=m;i++)printf("%d\n",ret[i]);
return 0;
}
bzoj 2780的更多相关文章
- 三种做法:BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster
目录 题意 思路 AC_Code1 AC_Code2 AC_Code3 参考 @(bzoj 2780: [Spoj]8093 Sevenk Love Oimaster) 题意 链接:here 有\(n ...
- BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )
全部串起来做SA, 在按字典序排序的后缀中, 包含每个询问串必定是1段连续的区间, 对每个询问串s二分+RMQ求出包含s的区间. 然后就是求区间的不同的数的个数(经典问题), sort queries ...
- bzoj 3277 串 && bzoj 3473 字符串 && bzoj 2780 [Spoj]8093 Sevenk Love Oimaster——广义后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277 https://www.lydsy.com/JudgeOnline/problem.p ...
- bzoj 3277 & bzoj 3473,bzoj 2780 —— 广义后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277 https://www.lydsy.com/JudgeOnline/problem.p ...
- BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster [广义后缀自动机]
JZPGYZ - Sevenk Love Oimaster Oimaster and sevenk love each other. But recently,sevenk hea ...
- BZOJ.2780.[SPOJ8093]Sevenk Love Oimaster(广义后缀自动机)
题目链接 \(Description\) 给定n个模式串,多次询问一个串在多少个模式串中出现过.(字符集为26个小写字母) \(Solution\) 对每个询问串进行匹配最终会达到一个节点,我们需要得 ...
- 【刷题】BZOJ 2780 [Spoj]8093 Sevenk Love Oimaster
Description Oimaster and sevenk love each other. But recently,sevenk heard that a girl named ChuYuXu ...
- bzoj 2780: [Spoj]8093 Sevenk Love Oimaster(广义SAM)
题目大意:给出n个原串,再给出m个查询串.求每个查询串出现在了多少原串中. 题解 直接对原串建一个广义SAM,然后把每一个原串放到SAM上跑一跑,记录一下每一个状态属于多少个原串,用$size$表示. ...
- BZOJ 2780 [Spoj]8093 Sevenk Love Oimaster ——广义后缀自动机
给定n个串m个询问,问每个串在n个串多少个串中出现了. 构建广义后缀自动机,(就是把所有字符串的后缀自动机合并起来)其实只需要add的时候注意一下就可以了. 然后对于每一个串,跑一边匹配,到达了now ...
随机推荐
- Redisson 分布式锁
Redisson_百度百科https://baike.baidu.com/item/Redisson/20856570 redission 分布式锁 - 穆穆兔兔 - 博客园https://www.c ...
- 安全工具acunetix使用
今天来主要介绍了安全测试工具AWVS(acunetix web vulnerability scanner)的使用 1) 安装包的下载地址:https://github.com/jiyanjiao/ ...
- BZOJ 3613: [Heoi2014]南园满地堆轻絮(二分)
题面: https://www.lydsy.com/JudgeOnline/problem.php?id=3613 题解: 考虑前面的数越小答案越优秀,于是我们二分答案,判断时让前面的数达到所能达到的 ...
- python之路day01--变量
一.变量 变量就是将一些运算的中间结果暂存到内存中,以便后续代码块调用. 规范: 1.必须由数字.字母.下划线任意组合,且不能数字开头. 2.不能是python中的关键字.如:‘print’ 'and ...
- Tomcat 日志文件分割
新到公司, 拿到了前辈们留下的 程序 “病历书” , 上面记载了项目上的一些 经常会犯的毛病, 还有相应的解决方法. 其中有的是因为后台 代码逻辑上的一些原因 , N手代码通病了吧 (这个还是以后再 ...
- 分布式监控系统开发【day38】:监控trigger表结构设计(一)
一.需求讨论 1.zabbix触发器的模板截图 1.zabbix2.4.7 2.zabbix3.0 2.模板与触发器关联的好处 好处就是可以批量处理,比如我说我有1000机器都要监控cpu.内存.IO ...
- 深入浅出mybatis之useGeneratedKeys参数用法
目录 在settings元素中设置useGeneratedKeys参数 在xml映射器中配置useGeneratedKeys参数 在接口映射器中设置useGeneratedKeys参数 在MyBati ...
- [再寄小读者之数学篇](2014-06-22 求极限 [中国科学技术大学2011年高等数学B考研试题])
设数列 $\sed{x_n}$ 满足 $0<x_1<\pi$, $x_{n+1}=\sin x_n\ (n=1,2,\cdots)$. (1) 证明 $\dps{\vlm{n}x_n}$ ...
- Chrome 禁止从页面打开 Data URI 网址了
现如今,网民的网络账户被盗,很有可能是被“钓鱼”了.去年的一份安全报告中指出:“近85%的资金损失是通过钓鱼网址泄露支付信息造成的”. 传统的钓鱼网站通常是申请一个和被冒充网站相似的域名,比如 tao ...
- Python DB operation
mysql http://www.cnblogs.com/zhangzhu/archive/2013/07/04/3172486.html 1.连接到本机上的MYSQL.首先打开DOS窗口,然后进入目 ...