[BZOJ2754] 喵星球上的点名 - AC自动机/后缀数组/后缀自动机/玄学♂暴力

纸张蒟蒻zzt只会写sam只会套板子qaq

#include"bits/stdc++.h"
using namespace std;

#define mmap(x,y) make_pair(x,y)
#define fge getchar()
template <class MyInt>
inline void read(MyInt&x){
	x=0;int f=1;char ch=fge;
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=fge;}
	while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=fge;
	x=x*f;
}

const int N=20005,M=50005,L=100005;
struct node{
	map<int,node*> go;
	set<int> res;
	node * fail;
	int len;
	node ();
} *null= new node(), e[2*L+4*N];
node::node (){
	fail=null;
	len=0;
};

set<int>un;

struct SAM{
	int str[L+2*N],l,tot,n,m,match[N],tmp,res[N];
	node *last;
	#define E map<int,node*>::iterator
	SAM(){last=&e[1];tmp=1;}
	void extend(int c,int value){
		node*p=last,*np=&e[++tmp];last=np;
		np->len=p->len+1;np->res.insert(value);
		while(p->go.find(c)==p->go.end()&&p!=null)
			p->go.insert(mmap(c,np)),p=p->fail;
		if(p==null) np->fail=e+1;
		else {
			node*q=p->go.find(c)->second,*nq;
			if(q->len==p->len+1)np->fail=q;
			else {
				nq=&e[++tmp];
				for(E i=q->go.begin();i!=q->go.end();i++)
					nq->go.insert(*i);
				nq->len=p->len+1;nq->fail=q->fail;
				np->fail=q->fail=nq;node*i;E j;
				for(i=p;(j=i->go.find(c))!=i->go.end()&&j->second==q;i=i->fail)
					j->second=nq;
			}
		}
	}
	int s[2*L+4*N],q[2*L+4*N];
	void pre(){
		read(n),read(m);int i,p,j;
		for(i=1;i<=n;i++){
			for(j=l+1,read(p);j<=l+p;j++)
				read(str[j]),extend(str[j],i);
			l+=p+1;str[l]=10001;extend(str[l],0);
			for(j=l+1,read(p);j<=l+p;j++)
				read(str[j]),extend(str[j],i);
			l+=p+1;str[l]=10001;extend(str[l],0);
		}
		for(i=1;i<=tmp;i++)s[e[i].len]++;
		for(i=1;i<=tmp;i++)s[i]+=s[i-1];
		for(i=tmp;i;i--)q[s[e[i].len]--]=i;
		for(i=tmp;i;i--){
			set<int>::iterator j;
			if(e[q[i]].res.empty()) continue;
			for(j=e[q[i]].res.begin();j!=e[q[i]].res.end();j++)
				e[q[i]].fail->res.insert(*j);
		}
		e[1].res.clear();
		null->res.clear();
	}
	void work(){
		int i,p,j,ans;
		for(i=1;i<=m;i++){
			node*now=e+1;
			for(j=1,read(p);j<=p;j++){
				read(match[j]);
				E w=now->go.find(match[j]);
				if(w==now->go.end())now=null;
				else now=w->second;
			}
			ans=now->res.size();
			set<int>::iterator k;
			for(k=now->res.begin();k!=now->res.end();k++)
				res[*k]++;
			printf("%d\n",ans);
		}
		for(i=1;i<n;i++)
			printf("%d ",res[i]);
		printf("%d",res[n]);
	}
} sam;

int main(){
	sam.pre();sam.work();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值