码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-01-22 11:11:59      阅读:305      评论:0      收藏:0      [点我收藏+]

标签:bzoj2780   spoj8093   sevenk love oimaster   后缀自动机   树状数组   

#include <stdio.h>
int main()
{
	puts("转载请注明出处谢谢");
	puts("http://blog.csdn.net/vmurder/article/details/43015849");
}

题意:

n,m

n个串

m个串

样例里面倒数第二行的you应该扔到下一行。


问m个串每个在前n个串中的几个出现过。


题解:

首先这道题跟

【BZOJ2754】【SCOI2012】喵星球上的点名

是一样的,只不过更卡时一点,或者说喵的数据太弱。


这道题虽然是后缀自动机,但是大体思路和

【BZOJ2434】【NOI2011】阿狸的打字机 AC自动机

是一样的。都是dfs序+树状数组优化


好了,说这道题。

就是我们建广义后缀树【就是多串的反序后缀自动机】

然后根据dfs序快速转移,用树状数组维护某区间有多少个不同的串。

我来贴两个详细的 题解 网址

16bitwar:http://blog.csdn.net/jiangyuze831/article/details/42964105

wyfcyx:http://wyfcyx.is-programmer.com/posts/76391.html

代码:

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 201000
#define T 26
using namespace std;

struct Suffix_Tree // 广义后缀树
{
	int head[N],next[N],v[N],cnt;
	void add(int u,int _v)
	{
		v[++cnt]=_v;
		next[cnt]=head[u];
		head[u]=cnt;
	}
	int in[N],out[N],dfn,stk[N];
	void build_dfn(int x)
	{
		in[x]=++dfn;
		stk[dfn]=x;
		for(int i=head[x];i;i=next[i])
			build_dfn(v[i]);
		out[x]=dfn;
	}
}sft,belong;

struct QUERY
{
	int id,p;
	QUERY(int _id=0,int _p=0):id(_id),p(_p){}
	bool operator < (const QUERY &a)const
		{return sft.out[p]<sft.out[a.p];}
}ask[N];
int vis[N],ans[N];
char s[N];
int n,m;

struct FENWICK
{
	int a[N],cnt[N];
	void add(int p,int x){for(;p<N;p+=p&-p)a[p]+=x;}
	int query(int p)
	{
		int ans=0,temp=p;
		for(p=sft.out[temp] ;p;p-=p&-p)ans+=a[p];
		for(p=sft.in[temp]-1;p;p-=p&-p)ans-=a[p];
		return ans;
	}
}fw;

struct SAM // 广义后缀自动机
{
	map<int,int>next[N];
	int pa[N],deep[N];
	int root,last,cnt;
	int newnode(int dep){deep[++cnt]=dep;return cnt;}
	void init(){root=last=cnt=1;}
	void add(char alp,int id) // 建立广义后缀自动机
	{
		int np=next[last][alp];
		if(np)
		{
			if(deep[np]==deep[last]+1)last=np;
			else {
				int nq=newnode(deep[last]+1);
				pa[nq]=pa[np],pa[np]=nq;
				next[nq]=next[np];
				int p=last;
				while(p&&next[p][alp]==np)
					next[p][alp]=nq,p=pa[p];
				last=nq;
			}
		}
		else {
			np=newnode(deep[last]+1);
			int p=last;
			while(p&&!next[p][alp])next[p][alp]=np,p=pa[p];
			if(!p)pa[np]=root;
			else {
				int q=next[p][alp];
				if(deep[q]==deep[p]+1)pa[np]=q;
				else {
					int nq=newnode(deep[p]+1);
					pa[nq]=pa[q],pa[q]=pa[np]=nq;
					next[nq]=next[q];
					while(p&&next[p][alp]==q)
						next[p][alp]=nq,p=pa[p];
				}
			}
			last=np;
		}
		belong.add(last,id);
	}
	void build_sft(){for(int i=2;i<=cnt;i++)sft.add(pa[i],i);}
	void deal_query()
	{
		bool find;
		int i,j,p;
		for(int i=1;i<=m;i++)
		{
			scanf("%s",s),find=1;
			for(p=root,j=0;s[j];j++)
			{
				if(!next[p][s[j]]){find=0;break;}
				p=next[p][s[j]];
			}
			if(find)ask[i]=QUERY(i,p);
			else ask[i]=QUERY(i,-1);
		}
		sort(ask+1,ask+m+1);
	}
}sam;

int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	scanf("%d%d",&n,&m);
	sam.init();
	for(i=1;i<=n;i++)
	{
		scanf("%s",s);
		sam.last=sam.root;
		for(j=0;s[j];j++)sam.add(s[j],i);
	}
	sam.build_sft();
	sft.build_dfn(1);
	sam.deal_query();
	
	for(k=1;k<=m&&ask[k].p==-1;k++);
	for(j=1;j<=sam.cnt;j++)
	{
		int u=sft.stk[j];
		for(i=belong.head[u];i;i=belong.next[i])
		{
			int v=belong.v[i];
			fw.add(j,1);
			if(vis[v])fw.add(vis[v],-1);
			vis[v]=j;
		}
		while(sft.out[ask[k].p]==j)
		{
			ans[ask[k].id]=fw.query(ask[k].p);
			k++;
		}
	}
	for(i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}



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

标签:bzoj2780   spoj8093   sevenk love oimaster   后缀自动机   树状数组   

原文地址:http://blog.csdn.net/vmurder/article/details/43015849

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!