【BZOJ2780】[Spoj]8093 Sevenk Love Oimaster 广义后缀自动机

【BZOJ2780】[Spoj]8093 Sevenk Love Oimaster

Description

Oimaster and sevenk love each other.

    But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster.As a woman‘s nature, sevenk felt angry and began to check oimaster‘s online talk with ChuYuXun.    Oimaster talked with ChuYuXun n times, and each online talk actually is a string.Sevenk asks q questions like this,    "how many strings in oimaster‘s online talk contain this string as their substrings?"

Input

 
There are two integers in the first line, 
the number of strings n and the number of questions q.
And n lines follow, each of them is a string describing oimaster‘s online talk. 
And q lines follow, each of them is a question.
n<=10000, q<=60000 
the total length of n strings<=100000, 
the total length of q question strings<=360000
 

Output

For each question, output the answer in one line.

Sample Input

3 3
abcabcabc
aaa
aafe
abc
a
ca

Sample Output

1
3
1

题意:给你一堆文本串,每次询问一个串在多少个文本串中出现过。

题解:多串匹配要用到广义SAM。就是在每当开始加入一个串的时候,将last指针变回root。

那么这题怎么搞?我们需要知道SAM中的每个节点被多少个文本串所包含。记录sum[i]表示i被多少个文本串包含,vis[i]表示当前时刻,最后一个包含i的文本串是哪个。在建完SAM后,我们将所有串在SAM上再跑一边,将经过的点,以及它的parent树上的所有祖先都更新一遍(因为一个点被影响后它的所有parent也要被影响),如果某个点的vis=当前时间,则退出,否则更新sum和vis。

时间复杂度我不太会证,大概O(nsqrt(n))吧?不过这题也有O(nlogn)的做法,就是求出parent树的DFS序,每次询问相当于问一个点在parent树的子树中有多少个不同的文本串,也就转换成在DFS序上的一段区间中有多少个不同的文本串。这个显然是HH的项链啊,不过感觉好麻烦。(懒)

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,m,tot;
int pre[400010],ch[400010][26],mx[400010],s[400010],vis[400010],lp[400010],rp[400010];
char str[800010];
void updata(int x,int y)
{
	for(;x&&vis[x]!=y;x=pre[x])	s[x]++,vis[x]=y;
}
int extend(int x,int y,int p)
{
	int np=++tot;
	mx[np]=mx[p]+1;
	for(;p&&!ch[p][x];p=pre[p])	ch[p][x]=np;
	if(!p)	pre[np]=1;
	else
	{
		int q=ch[p][x];
		if(mx[q]==mx[p]+1)	pre[np]=q;
		else
		{
			int nq=++tot;
			pre[nq]=pre[q],pre[np]=pre[q]=nq,mx[nq]=mx[p]+1;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
			for(;p&&ch[p][x]==q;p=pre[p])	ch[p][x]=nq;
		}
	}
	return np;
}
int main()
{
	scanf("%d%d",&n,&m);
	int i,j,a,b;
	tot=1;
	for(i=1;i<=n;i++)
	{
		lp[i]=rp[i-1];
		scanf("%s",str+lp[i]);
		rp[i]=strlen(str);
		for(b=1,j=lp[i];j<rp[i];j++)	b=extend(str[j]-‘a‘,i,b);
	}
	for(i=1;i<=n;i++)
		for(a=1,j=lp[i];j<rp[i];j++)	a=ch[a][str[j]-‘a‘],updata(a,i);
	for(i=1;i<=m;i++)
	{
		scanf("%s",str);
		a=strlen(str);
		for(b=1,j=0;j<a;j++)
		{
			if(ch[b][str[j]-‘a‘])	b=ch[b][str[j]-‘a‘];
			else	break;
		}
		if(j==a)	printf("%d\n",s[b]);
		else	printf("0\n");
	}
	return 0;
}
时间: 2024-10-25 17:29:54

【BZOJ2780】[Spoj]8093 Sevenk Love Oimaster 广义后缀自动机的相关文章

BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster [广义后缀自动机]

JZPGYZ - Sevenk Love Oimaster     Oimaster and sevenk love each other.       But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster. As a woman's nature, sevenk felt angry and began to check oimaster's online talk with ChuYuXun

BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )

全部串起来做SA, 在按字典序排序的后缀中, 包含每个询问串必定是1段连续的区间, 对每个询问串s二分+RMQ求出包含s的区间. 然后就是求区间的不同的数的个数(经典问题), sort queries + BIT 就行了.时间复杂度O(N log N). 速度垫底了QAQ 你们都会SAM.... ---------------------------------------------------------------------- #include<cmath> #include<c

BZOJ 2780 SPOJ 8093 Sevenk Love Oimaster 后缀自动机+fenwick

题目大意:给出一些字符串,给出一些询问,每次问当前串在源串中的几个中出现过. 思路:将所有源串建立广义后缀自动机.每次新的一个串的时候,把last清成root,往里面加的时候,如果last指针往下走的时候已经有节点了,就需要拓展一个新的节点出来,否则就不满足广义后缀自动机的性质.此外,每一个节点代表的不一定是一个串,可能代表的是多个串的子串,所以要在每个点后面挂链,来表示这个节点是属于哪几个串中的子串.后面的事情就比较简单了,把后缀树建立出来,弄出DFS序,离线处所有询问,变成在一段序列中出现过

【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机

[BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建了n-1条边将它们连通起来.也就是说,这n块空地形成了一个树的结构. 有n个粉丝们来到了太阳花田上.为了表达对幽香生日的祝

E. Three strings 广义后缀自动机

http://codeforces.com/problemset/problem/452/E 多个主串的模型. 建立一个广义后缀自动机,可以dp出每个状态的endpos集合大小.同时也维护一个R[]表示那个串出现过. 所以可以算出每个状态的dp[i][k]表示第k个串在第i个状态中出现的次数. 可以知道sigma dp[i][0...k]是等于  endpos集合的大小. 然后把这个贡献加到min(i)....max(i)中去就可以了 差分一下. #include <bits/stdc++.h>

BZOJ 3277 串 (广义后缀自动机)

3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 输出一行n个整数,第i个整数表示第i个字符串的答案. Sa

广义后缀自动机

1).自动机的介绍 首先我们先来介绍一下什么是自动机,有限状态自动机的功能是识别字符串,令一个自动机A,若他能识别字符串S,就记为A(S)=Ture,否则A(S)=False. 自动机由五个部分组成,alpha:字符集,state:状态集合,init:初始状态,end:结束状态集合,trans:状态转移函数. 令trans(s,ch)表示当前状态是s,在读入字符ch之后,所到达的状态.如果trans(s,ch)这个转移不存在,为了方便,设其为null,同时null只能转移到null.null表示

hdu 5853 Jong Hyok and String(广义后缀自动机)

题目链接:hdu 5853 Jong Hyok and String 题意: 给你n个字符串,m个询问,每次询问一个字符串 定义set(s)={(i,j)} 表示 s在第i个字符串中出现,且末尾位置为j. 对于一个询问,求set(Qi)=set(t) ,t串的数量. 题解: 如果是n=1,那么就是后缀自动机的一道裸题,答案就是Qi串匹配的最后一个节点x,ml[x]-ml[f[x]]. 现在是多个串,那么就建立一个广义后缀自动机.每次插入一个串后,将last=root,然后继续插下一个就行了. 最

【SPOJ】Longest Common Substring(后缀自动机)

[SPOJ]Longest Common Substring(后缀自动机) 题面 Vjudge 题意:求两个串的最长公共子串 题解 \(SA\)的做法很简单 不再赘述 对于一个串构建\(SAM\) 另外一个串在\(SAM\)上不断匹配 最后计算答案就好了 匹配方法: 如果\(trans(s,c)\)存在 直接沿着\(trans\)走就行,同时\(cnt++\) 否则沿着\(parent\)往上跳 如果存在\(trans(now,c),cnt=now.longest+1\) 否则,如果不存在可行的