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;
}



相关文章推荐

BZOJ2780——[Spoj]8093 Sevenk Love Oimaster

0、题意:给定N个原始字符串S,M次查询某个特殊的字符串S’在多少个原始串中出现过。 1、分析:这个题我们第一感觉就是可以用后缀自动机来搞,然后我们发现不是本质不同的字串。。求出现过的次数,也就是说...

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

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

BZOJ 2780 后缀自动机

由于是英文题,简要解释一下题目。开始给出n个子串,和m个询问,对于每个询问读入一个子串,询问n个子串中,有多少个子串包含所询问的子串。实在看不懂的可以从样例中意会一下。#include #inclu...

poj2780Linearity【共线】

Language: Default Linearity Time Limit: 3000MS   Memory Limit: 65536K Total Subm...

【HDU2780 - Su-Su-Sudoku】 解题报告+思路+代码,差点一次AC T^T

#include #include #include #include #include ////#define INPUT ///#define DBG /** Problem: ...

hdu 2780 Su-Su-Sudoku(DFS数独)

题目链接:hdu2780 #include #include #include #include #include #define N 15 using namespace std; int map...

【HDU】2780 Su-Su-Sudoku【数独】精确覆盖

传送门:【HDU】2780 Su-Su-Sudoku【数独】

Linerarity(P2780)

这个可以先排好序,然后计算出的后面的点的关系与前面的点的已经没有关系,既然有关系前面的点已经计算过。然后排好序(这里不会费多少时间的)找出有多少共线即可。 #include #include...

BZOJ题目镜像

  • 2014年09月14日 12:18
  • 15.01MB
  • 下载

POJ 1118,2606,2780,3512

四题题意都是问一个平面上很多离散点,问一条直线最多能串起几条,作为糖葫芦控毫无压力呀喵哈哈~买一送三的题当然做了OTZ…区别貌似就是2780说明没有重点;2606坐标有负数,没重点;3512是升级版数...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj-2780 Sevenk Love Oimaster
举报原因:
原因补充:

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