bzoj-2780 Sevenk Love Oimaster

原创 2015年11月19日 07:43:16

题意:

给出n个字符串和m个询问串;

求每个询问串是多少个字符串的子串;

n<=10000,m<=60000;

字符串总长度<=100000,询问串总长度<=360000;


题解:

传说中的多串匹配用的广义后缀自动机;

构建上的不同只在当trans(last,x)这个状态存在的时候,要进行一个讨论;

(当然,在单串的自动机中last不会有任何trans转移,所以这种情况只会在广义后缀自动机中出现;

具体就是如果last和trans(last,x)的len只差个1,那么trans(last,x)就是我们这次要插入的结点了,直接返回;

不然,就像下面的一样复制一个trans(last,x)结点搞一搞就可以了;

然后为了区分所有字符串 的后缀,我们在后缀结点上挂链标记就可以了;


对于一个输入的询问串,这个问题就等价于在广义后缀树上找到能代表这个串的结点,然后查询这个结点的子树内不同颜色数;

这个东西很像那个HH的项链嘛,搞出来个DFS序,然后预处理所有结点的答案即可;

因为这个问题最多有O(n)种询问,也就是说可以预处理出来之后再在线回答咯;


代码:


#include<map>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define M 370000
#define K 70000
using namespace std;
char str[M];
int next[N<<1],to[N<<1],head[N<<1],pre[N],ce,tim;
int sum[N<<1],ans[N<<1];
namespace col
{
	int next[N<<1],val[N<<1],head[N<<1],ce;
	int add(int x,int y)
	{
		val[++ce]=y;
		next[ce]=head[x];
		head[x]=ce;
	}
}
int add(int x,int y)
{
	to[++ce]=y;
	next[ce]=head[x];
	head[x]=ce;
}
int lowbit(int x)
{
	return x&(-x);
}
void update(int x,int val)
{
	if(!x)	return ;
	while(x<N<<1)
	{
		sum[x]+=val;
		x+=lowbit(x);
	}
}
int query(int x)
{
	int ret=0;
	while(x)
	{
		ret+=sum[x];
		x-=lowbit(x);
	}
	return ret;
}
void dfs(int x)
{
	int t=++tim;
	for(int i=col::head[x];i;i=col::next[i])
	{
		update(pre[col::val[i]],-1);
		update(t,1);
		pre[col::val[i]]=t;
	}
	for(int i=head[x];i;i=next[i])
	{
		dfs(to[i]);
	}
	ans[x]=query(tim)-query(t-1);
}
namespace SAM
{
	int len[N<<1],pre[N<<1];
	map<char,int>son[N<<1];
	int tot,last;
	int newnode()
	{
		tot++;
//		len[tot]=pre[tot]=0;
//		son[tot].clear();
		return tot;
	}
	void init()
	{
		tot=0;
		last=newnode();
	}
	void Insert(char x,int i)
	{
		if(son[last][x])
		{
			int p=son[last][x];
			if(len[p]==len[last]+1)
				last=p;
			else
			{
				int np=newnode();
				len[np]=len[last]+1;
				pre[np]=pre[p];
				pre[p]=np;
				son[np]=son[p];
				for(int q=last;son[q][x]==p;q=pre[q])
					son[q][x]=np;
				last=np;
			}
		}
		else
		{
			int p,np=newnode();
			len[np]=len[last]+1;
			for(p=last;p&&!son[p][x];p=pre[p])
				son[p][x]=np;
			if(!p)
				pre[np]=1;
			else
			{
				int q=son[p][x];
				if(len[q]==len[p]+1)
					pre[np]=q;
				else
				{
					int nq=newnode();
					len[nq]=len[p]+1;
					pre[nq]=pre[q];
					son[nq]=son[q];
					pre[q]=pre[np]=nq;
					for(;son[p][x]==q;p=pre[p])
						son[p][x]=nq;
				}
			}
			last=np;
		}
		col::add(last,i);
	}
	void Build()
	{
		for(int i=1;i<=tot;i++)
			add(pre[i],i);
	}
	int query(char *s)
	{
		int p=1;
		while(*s!='\0')
			p=son[p][*s],s++;
		return p;
	}
}
int main()
{
	int n,m,len,i,j,k;
	scanf("%d%d",&n,&m);
	SAM::init();
	for(i=1;i<=n;i++)
	{
		scanf("%s",str+1);
		len=strlen(str+1);
		SAM::last=1;
		for(j=1;j<=len;j++)
			SAM::Insert(str[j],i);
	}
	SAM::Build();
	dfs(1);
	for(i=1;i<=m;i++)
	{
		scanf("%s",str);
		printf("%d\n",ans[SAM::query(str)]);
	}
	return 0;
}



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

题目大意:给出一些字符串,给出一些询问,每次问当前串在源串中的几个中出现过。 思路:将所有源串建立广义后缀自动机。每次新的一个串的时候,把last清成root,往里面加的时候,如果last指...
  • jiangyuze831
  • jiangyuze831
  • 2015年01月21日 09:55
  • 1587

【BZOJ2780】【Spoj8093】 Sevenk Love Oimaster 后缀自动机

题意: n,m n个串 m个串 样例里面倒数第二行的you应该扔到下一行。 问m个串每个在前n个串中的几个出现过。 题解: 首先这道题跟 【BZOJ2754】【SCOI2012】喵星球上的点名...
  • Vmurder
  • Vmurder
  • 2015年01月22日 10:22
  • 1995

BZOJ2780 [Spoj]8093 Sevenk Love Oimaster

啊……建个广义后缀自动机搞搞就行了,好像也不需要树状数组dfs序什么的啊 每个串暴力跳一遍,不跳这个串跳过的点就好了 复杂度好像是对的?但是我不会证,不过好多题都这么过掉了 #include #inc...
  • neither_nor
  • neither_nor
  • 2017年02月28日 07:28
  • 356

2780: [Spoj]8093 Sevenk Love Oimaster

之前由于一直懒得绑定于是就没写了。。。。。。 看一下这道题,直接建广义后缀自动机,然后对于每一个新建的点把它的祖先标记一下在这个字符串中出现过就好了 开心的码完就1A了,爽...
  • qq_36797743
  • qq_36797743
  • 2017年06月26日 15:34
  • 97

[bzoj2780][Spoj]8093 Sevenk Love Oimaster

题目大意给定n个字符串,q个询问,每个询问给定一个字符串,求它在n个字符串中多少个中以连续子串形式出现。n...
  • WorldWide_D
  • WorldWide_D
  • 2017年03月16日 22:31
  • 357

[BZOJ2780][Spoj8093]Sevenk Love Oimaster(广义后缀自动机)

题目描述传送门题解对于所有的模板串建立广义后缀自动机,对于每一个点统计一下right集合中有几个模板串 然后对于所有的查询串在后缀自动机上匹配,然后看一下最终匹配到的那个点有几个模板串就行了 具体...
  • Clove_unique
  • Clove_unique
  • 2017年03月30日 11:40
  • 627

Sevenk Love Oimaster(trie,MAP后缀自动机)

题意:给出n个串,再m个询问,每次询问一个串s,问给出的n个串中,子串包含s的有几个 解法:给这n个串建立trie,再将trie建成sam,然后我们要知道的是,对于每一个状态u所表示的子串,被几个串...
  • No__stop
  • No__stop
  • 2014年11月01日 13:19
  • 1038

bzoj2780 [Spoj]8093 Sevenk Love Oimaster

题目链接分析: 我一开始的想法比较简单,建出SAMSAM,每个结点记录有多少串使用了这个结点,直接匹配即可 结果竟然T了,按理来说也应该是WA啊在看学姐的blog的时候,发现实际上就是这么搞:我们...
  • wu_tongtong
  • wu_tongtong
  • 2018年01月30日 15:56
  • 26

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

广义后缀自动机其实就是简单的把所有的串都插到了一起而已。。。。 每添加进一个新的字符其实影响到的字串也就是能新增加的字串就是fail链上的,每一次新加入一个字符向上更新影响就好了#include #...
  • pbihao
  • pbihao
  • 2017年03月21日 21:54
  • 95

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

2780: [Spoj]8093 Sevenk Love Oimaster Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 738  Solved:...
  • clover_hxy
  • clover_hxy
  • 2016年12月24日 16:21
  • 657
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj-2780 Sevenk Love Oimaster
举报原因:
原因补充:

(最多只允许输入30个字)