BZOJ 2754 SCOI2012 喵星球上的点名 fail树+set启发式合并

题目大意:给定n个目标串和m个模式串,问这m个模式串每个在多少个目标串中出现过,以及n个目标串每个以最多多少个模式串为子串

我错了……就算用fail树+set启发式合并也优化不到O(nlog^2n)……这题的数据范围相当无解啊

首先将所有名字和点名的字符串全都插进AC自动机

将每个点上开一个set记录这个点是哪些喵星人的名字的前缀

然后建立fail树 沿着fail树从下到上启发式合并

每合并完一个点 如果这个点是某次点名的字符串 那么这次点名点到的喵星人就是这个点的set中的所有元素 统计答案即可

统计答案以外的操作显然是O(nlog^2n) 但是统计答案这里还是没有避免高复杂度

最终复杂度为O(nlog^2n+Σans2) 其中ans2是第二问的答案

感觉这个算法的瓶颈就在Σans2上了……或许我们可以换一种做法统计ans2?感觉……不是很必要的样子……

#include <set>
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
struct Trie{
	Trie *fail;
	map<int,Trie*> son;
	set<int> s;
	vector<Trie*> fail_son;
	int ed,cnt;
}*root,mempool[M],*C=mempool;
int n,m,ans1[50500],ans2[20200];
int substitute[50500];
void Insert(Trie* &p,int left,int pos,bool flag)
{
	if(!p) p=C++;
	if(!flag) p->s.insert(pos);
	if(!left)
	{
		if(flag)
		{
			if(p->ed)
				substitute[p->ed]=pos;
			p->ed=pos;
			p->cnt++;
		}
		return ;
	}
	int temp;
	scanf("%d",&temp);
	Insert(p->son[temp],left-1,pos,flag);
}
void Build_Tree()
{
	static Trie *q[M];
	static int r,h;
	map<int,Trie*>::iterator it;
	for(it=root->son.begin();it!=root->son.end();it++)
	{
		it->second->fail=root;
		root->fail_son.push_back(it->second);
		q[++r]=it->second;
	}
	while(r!=h)
	{
		Trie *p=q[++h];
		for(it=p->son.begin();it!=p->son.end();it++)
		{
			Trie *temp=p->fail;
			while(temp!=root&&!temp->son[it->first])
				temp=temp->fail;
			if(temp->son[it->first])
				temp=temp->son[it->first];
			it->second->fail=temp;
			temp->fail_son.push_back(it->second);
			q[++r]=it->second;
		}
	}
}
void DFS(Trie *p)
{
	vector<Trie*>::iterator it;
	set<int>::iterator _it;
	for(it=p->fail_son.begin();it!=p->fail_son.end();it++)
	{
		DFS(*it);
		set<int>&s=p->s;
		set<int>&son_s=(*it)->s;
		if( s.size()<son_s.size() )
			swap(s,son_s);
		for(_it=son_s.begin();_it!=son_s.end();_it++)
			s.insert(*_it);
		son_s.clear();
	}
	if(p->ed)
	{
		ans1[p->ed]=p->s.size();
		for(_it=p->s.begin();_it!=p->s.end();_it++)
			ans2[*_it]+=p->cnt;
	}
}
int main()
{
	int i,x;
	cin>>n>>m;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&x);
		Insert(root,x,i,0);
		scanf("%d",&x);
		Insert(root,x,i,0);
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d",&x);
		Insert(root,x,i,1);
	}
	Build_Tree();
	DFS(root);
	for(i=m;i;i--)
		if(substitute[i])
			ans1[i]=ans1[substitute[i]];
	for(i=1;i<=m;i++)
		printf("%d\n",ans1[i]);
	for(i=1;i<=n;i++)
		printf("%d%c",ans2[i],i==n?'\n':' ');
	return 0;
}
时间: 2024-12-13 14:03:30

BZOJ 2754 SCOI2012 喵星球上的点名 fail树+set启发式合并的相关文章

BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

BZOJ 2754([SCOI2012]喵星球上的点名-后缀数组统计序列集合中子序列出现次数)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 805  Solved: 380 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,

BZOJ 2754: [SCOI2012]喵星球上的点名

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1926  Solved: 850[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这

bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1359  Solved: 618[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

bzoj 2754 [SCOI2012]喵星球上的点名 (AC自动机+map维护Trie树)

题目大意:略 由于字符集大,要用map维护Trie树 并不能用AC自动机的Trie图优化,不然内存会炸 所以我用AC自动机暴跳fail水过的 显然根据喵星人建AC自动机是不行的,所以要根据问题建 然而这题有一些很艮的地方: 1.如果一个喵的名和姓都被点到,那他只被点到了一次 2.询问的串可能相同 3.如果map中并不包含某个元素,但你强行用数组表示它,那么它会返回0,然后这个元素会被强行插入map并赋值成0 1 #include <map> 2 #include <queue> 3

bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 2745 Solved: 1190 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么

P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队)

P2336 [SCOI2012]喵星球上的点名 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> #define rint register int using namespace std; int read(){ char c=getchar();int x=0; while(

洛谷 P2336 [SCOI2012]喵星球上的点名

题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 N 个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M 个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到. 然而,由于喵星人的字码过于古怪,以至于不能用 ASCII 码来表示.为了方便描述,a180285 决定用数串来表示喵星人的名字. 现在你能帮助 a180285 统计每次点名的时候有多少喵星人答到,以及 M 次点名结

[BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组

a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到. 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示.为了方便描述,a180285决定用数串来表示喵星人的名字. 现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?