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

题目大意:给出一些字符串,给出一些询问,每次问当前串在源串中的几个中出现过。

思路:将所有源串建立广义后缀自动机。每次新的一个串的时候,把last清成root,往里面加的时候,如果last指针往下走的时候已经有节点了,就需要拓展一个新的节点出来,否则就不满足广义后缀自动机的性质。此外,每一个节点代表的不一定是一个串,可能代表的是多个串的子串,所以要在每个点后面挂链,来表示这个节点是属于哪几个串中的子串。后面的事情就比较简单了,把后缀树建立出来,弄出DFS序,离线处所有询问,变成在一段序列中出现过多少不同的数字,弄一个树状数组维护一下。

其实和喵星球上的点名是差不多的,但是那个题我用的后缀数组暴力的,这个题会T。

还有这个题坑爹的卡内存啊,字符集太大,直接建立肯定mle,用map的话就不能用指针,我这还是第一次用数组写啊。。DT死了。。。

CODE:

//#define _CRT_SECURE_NO_DEPRECATE

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 200010
using namespace std;

struct Graph{
	int head[MAX],total;
	int next[MAX],aim[MAX];

	void Add(int x,int y) {
		next[++total] = head[x];
		aim[total] = y;
		head[x] = total;
	}
}G,repre;

struct Ask{
	pair<int,int> interval;
	int id;

	Ask(pair<int,int> _,int __):interval(_),id(__) {}
	Ask() {}
	bool operator <(const Ask &a)const {
		return interval.second < a.interval.second;
	}
}ask[MAX];

int len[MAX],father[MAX];
map<int,int> tranc[MAX];
int cnt,root,last;

inline int NewNode(int _)
{
	len[++cnt] = _;
	return cnt;
}

void Initialize()
{
	root = last = NewNode(0);
}

inline void Add(int c,int i)
{
	int p = tranc[last][c];
	if(p) {
		if(len[p] == len[last] + 1)	last = p;
		else {
			int rep = NewNode(len[last] + 1);
			father[rep] = father[p];
			father[p] = rep;
			tranc[rep] = tranc[p];
			for(int temp = last; temp && tranc[temp][c] == p; temp = father[temp])
				tranc[temp][c] = rep;
			last = rep;
		}
	}
	else {
		int np = NewNode(len[last] + 1);
		for(p = last; p && !tranc[p][c]; p = father[p])
			tranc[p][c] = np;
		if(!p)	father[np] = root;
		else {
			int q = tranc[p][c];
			if(len[q] == len[p] + 1)	father[np] = q;
			else {
				int nq = NewNode(len[p] + 1);
				father[nq] = father[q];
				father[q] = father[np] = nq;
				tranc[nq] = tranc[q];
				for(; p && tranc[p][c] == q; p = father[p])
					tranc[p][c] = nq;
			}
		}
		last = np;
	}
	repre.Add(last,i);
}

pair<int,int> subtree[MAX];
int seq[MAX],_clock;

void DFS(int x)
{
	seq[++_clock] = x;
	subtree[x].first = _clock;
	for(int i = G.head[x]; i; i = G.next[i])
		DFS(G.aim[i]);
	subtree[x].second = _clock;
}

char s[MAX << 1];

inline pair<int,int> Find()
{
	int now = root,length = strlen(s);
	for(int i = 0; i < length; ++i) {
		if(!tranc[now][s[i]])	return make_pair(-1,-1);
		now = tranc[now][s[i]];
	}
	return subtree[now];
}

int fenwick[MAX];

inline void Fix(int x,int c)
{
	for(; x <= cnt; x += x&-x)
		fenwick[x] += c;
}

inline int GetSum(int x)
{
	int re = 0;
	for(; x; x -= x&-x)
		re += fenwick[x];
	return re;
}

int strings,asks;
int last_add[MAX],ans[MAX];

int main()
{
	Initialize();
	scanf("%d%d",&strings,&asks);
	for(int i = 1; i <= strings; ++i) {
		scanf("%s",s);
		int length = strlen(s);
		last = root;
		for(int j = 0; j < length; ++j)
			Add(s[j],i);
	}
	for(int i = 1; i <= cnt; ++i)
		if(father[i])
			G.Add(father[i],i);
	DFS(1);
	for(int i = 1; i <= asks; ++i) {
		scanf("%s",s);
		ask[i] = Ask(Find(),i);
	}
	sort(ask + 1,ask + asks + 1);

	int now = 1;
	while(ask[now].interval.first == -1 && now <= asks)	++now;
	for(int i = 1; i <= cnt; ++i) {
		for(int j = repre.head[seq[i]]; j; j = repre.next[j]) {
			int col = repre.aim[j];
			Fix(i,1);
			if(last_add[col])
				Fix(last_add[col],-1);
			last_add[col] = i;
		}
		for(; ask[now].interval.second == i; ++now)
			ans[ask[now].id] = GetSum(ask[now].interval.second) - GetSum(ask[now].interval.first - 1);
	}
	for(int i = 1; i <= asks; ++i)
		printf("%d\n",ans[i]);
	return 0;
}

时间: 2024-11-01 06:08:31

BZOJ 2780 SPOJ 8093 Sevenk Love Oimaster 后缀自动机+fenwick的相关文章

BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )

全部串起来做SA, 在按字典序排序的后缀中, 包含每个询问串必定是1段连续的区间, 对每个询问串s二分+RMQ求出包含s的区间. 然后就是求区间的不同的数的个数(经典问题), sort queries + BIT 就行了.时间复杂度O(N log N). 速度垫底了QAQ 你们都会SAM.... ---------------------------------------------------------------------- #include<cmath> #include<c

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

JZPGYZ - Sevenk Love Oimaster     Oimaster and sevenk love each other.       But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster. As a woman's nature, sevenk felt angry and began to check oimaster's online talk with ChuYuXun

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

[BZOJ2780][Spoj]8093 Sevenk Love Oimaster Description Oimaster and sevenk love each other.     But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster.As a woman's nature, sevenk felt angry and began to check oimaster's online t

【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]喵星球上的点名 是一样的,只不过更卡时一点,或者

【SPOJ】Distinct Substrings(后缀自动机)

[SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/endpos\)集合的大小 但是实际上我们没有任何必要减去不合法的数量 我们只需要累加每个节点表示的合法子串的数量即可 这个值等于\(longest-shortest+1=longest-parent.longest\) #include<iostream> #include<cstdio&g

【SPOJ】8222. Substrings(后缀自动机)

http://www.spoj.com/problems/NSUBSTR/ 题意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.求F(1)..F(Length(S)) 这题做法: 首先建立字符串的后缀自动机. 因为自动机中的每个状态都代表一类子串前缀,且任意状态的最长的|max|所对应的子串是唯一的. 所以我们算出每个子串(即找到的状态是end态),他们的right值为++(即保证长度为当前子串的出现次数为1),然后自底向上在parent树中更新right值(pare

BZOJ 4032 HEOI2015 最短不公共子串 后缀自动机+序列自动机+BFS

题目大意:给定字符串A和B,求A最短的子串/子序列S满足S不是B的子串/子序列 这题真TM有毒*2 搞法类似这道题 然后子串是后缀自动机 子序列自然就是序列自动机了= = 每更新一个x节点时所有没有x的后继的节点都连向这个节点 每个节点的parent是这个字母上一次出现的位置 每个字母记录最后一次出现的位置 更新指针时沿着parent指针撸一遍就行了 #include <cstdio> #include <cstring> #include <iostream> #in

【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】

题意 给出一个字符串,要你找出所有长度的子串分别的最多出现次数. 分析 我们建出后缀自动机,然后预处理出每个状态的cnt,cnt[u]指的是u这个状态的right集合大小.我们设f[len]为长度为len的子串的最多出现次数.我们对于自动机的每个状态都更新f,f[st[u].len]=max(f[st[u].len],cnt[u]).然后这样更新完以后,可以神奇的dp一下.f[len]=max(f[len],f[len+1]).想想为什么? 1 #include <cstdio> 2 #inc

后缀自动机初探

之前看过几次后缀自动机,然后因为人太蠢都没看懂. 最近重新填坑TAT... BZOJ4032: [HEOI2015]最短不公共子串 建出后缀自动机和序列自动机,然后我们知道自动机上每一条路径都相当于一个子串(子序列),这样只要从根节点开始bfs一遍,找到A有而B没有的,那就是字典序最小的辣. #include<cstring> #include<iostream> #include<algorithm> #include<cstdio> #include&l