BZOJ 3881 COCI 2015 Divljak

题面

Description

Tom有n个字符串S1,S2...Sn,Jerry有一个字符串集合T,一开始集合是空的。
接下来会发生q个操作,操作有两种形式:
“1 P”,Jerry往自己的集合里添加了一个字符串P。
“2 x”,Tom询问Jerry,集合T中有多少个字符串包含串Sx。(我们称串A包含串B,当且仅当B是A的子串)
Jerry遇到了困难,需要你的帮助。

Input

第1行,一个数n;
接下来n行,每行一个字符串表示Si;
下一行,一个数q;
接下来q行,每行一个操作,格式见题目描述。

Output

对于每一个Tom的询问,帮Jerry输出答案。

Sample Input

3
a
bc
abc
5
1 abca
2 1
1 bca
2 2
2 3

Sample Output

1
2
1

HINT

100%: \(1≤N,Q≤100000\), \(\sum_{s \in S} |s|, \sum_{s \in T}|s| \le 2 \times 10^6\), \(alphabet = \{a ... z\}\)

Solution

正解貌似是fail树加树链的并, 但我写的是后缀树. 还没读入完空间就炸了... 先放一份代码吧

#include <cstdio>
#include <cstring>
#include <vector>
#define vector std::vector

const int LEN = (int)2e6, N = (int)1e5, Q = (int)1e5;
int q;
int ans[Q];
struct segmentTree
{
	struct node
	{
		node *suc[2];
		int sz;
		inline node() {for(int i = 0; i < 2; ++ i) suc[i] = NULL; sz = 0;}
	}*rt;
	inline segmentTree() {rt = NULL;}
	node* insert(node *u, int L, int R, int pos)
	{
		if(u == NULL) u = new node;
		if(L == R) {u->sz = 1; return u;}
		if(pos <= L + R >> 1) u->suc[0] = insert(u->suc[0], L, L + R >> 1, pos); else u->suc[1] = insert(u->suc[1], (L + R >> 1) + 1, R, pos);
		u->sz = 0;
		for(int i = 0; i < 2; ++ i) if(u->suc[i] != NULL) u->sz += u->suc[i]->sz;
		return u;
	}
	inline void insert(int pos) {rt = insert(rt, 1, q, pos);}
	int query(node *u, int L, int R, int pos)
	{
		if(u == NULL) return 0;
		if(R <= pos) return u->sz;
		return query(u->suc[0], L, L + R >> 1, pos) + (pos > L + R >> 1 ? query(u->suc[1], (L + R >> 1) + 1, R, pos) : 0);
	}
	inline int query(int pos) {return query(rt, 1, q, pos);}
	node* merge(int L, int R, node *u, node *_u)
	{
		if(u == NULL) return _u; if(_u == NULL) return u;
		if(L == R) {u->sz |= _u->sz; delete _u; return u;}
		u->suc[0] = merge(L, L + R >> 1, u->suc[0], _u->suc[0]); u->suc[1] = merge((L + R >> 1) + 1, R, u->suc[1], _u->suc[1]);
		delete _u;
		u->sz = 0;
		for(int i = 0; i < 2; ++ i) if(u->suc[i] != NULL) u->sz += u->suc[i]->sz;
		return u;
	}
	inline void merge(segmentTree *T) {rt = merge(1, q, rt, T->rt);}
};
struct suffixAutomaton
{
	struct node
	{
		node *suc[26], *pre;
		int len;
		vector<int> bck, qry;
		int vst;
		vector<node*> successorOnSuffixTree;
		inline node() {for(int i = 0; i < 26; ++ i) suc[i] = NULL; pre = NULL; vst = 0; bck.clear(); qry.clear(); successorOnSuffixTree.clear();}
	}*rt;
	inline suffixAutomaton() {rt = new node; rt->len = 0;}
	inline node* insert(char *str, int len, int id)
	{
		node *lst = rt;
		for(int i = 0; i < len; ++ i)
		{
			int c = str[i] - 'a';
			if(lst->suc[c] != NULL)
			{
				node *p = lst->suc[c];
				if(p->len == lst->len + 1) { if(~ id) p->bck.push_back(id); lst = p; continue;}
				node *q = new node; if(~ id) q->bck.push_back(id);
				for(int i = 0; i < 26; ++ i) q->suc[i] = p->suc[i]; q->pre = p->pre; q->len = lst->len + 1;
				p->pre = q;
				for(; lst != NULL && lst->suc[c] == p; lst = lst->pre) lst->suc[c] = q;
				lst = q;
				continue;
			}
			node *u = new node; u->len = lst->len + 1; if(~ id) u->bck.push_back(id);
			for(; lst != NULL && lst->suc[c] == NULL; lst = lst->pre) lst->suc[c] = u;
			if(lst == NULL) u->pre = rt;
			else
			{
				node *p = lst->suc[c];
				if(p->len == lst->len + 1) u->pre = p;
				else
				{
					node *q = new node; for(int i = 0; i < 26; ++ i) q->suc[i] = p->suc[i]; q->pre = p->pre; q->len = lst->len + 1;
					u->pre = p->pre = q;
					for(; lst != NULL && lst->suc[c] == p; lst = lst->pre) lst->suc[c] = q;
				}
			}
			lst = u;
		}
		return lst;
	}
	void build(node *u)
	{
		u->vst = 1; if(u->pre != NULL) u->pre->successorOnSuffixTree.push_back(u);
		for(int i = 0; i < 26; ++ i) if(u->suc[i] != NULL && ! u->suc[i]->vst) build(u->suc[i]); 
	}
	inline void buildSuffixTree() {build(rt);}
	segmentTree* DFS(node *u)
	{
		segmentTree *seg = new segmentTree;
		for(auto id : u->bck) seg->insert(id);
		for(auto v : u->successorOnSuffixTree)
		{
			segmentTree *res = DFS(v);
			seg->merge(res);
		}
		for(auto qry : u->qry) ans[qry] = seg->query(qry);
		return seg;
	}
	inline void work() {DFS(rt);}
}SAM;
int main()
{
	
	#ifndef ONLINE_JUDGE
	
	freopen("davljak.in", "r", stdin);
	freopen("davljak.out", "w", stdout);
	
	#endif
	
	int n; scanf("%d\n", &n);
	static char str[LEN];
	static suffixAutomaton::node *ed[N + 1];
	for(int i = 1; i <= n; ++ i) scanf("%s", str), ed[i] = SAM.insert(str, strlen(str), -1);
	scanf("%d", &q);
	for(int i = 1; i <= q; ++ i)
	{
		int opt; scanf("%d ", &opt);
		if(opt == 1) scanf("%s", str), SAM.insert(str, strlen(str), i);
		else if(opt == 2)
		{
			int x; scanf("%d", &x);
			ed[x]->qry.push_back(i);
		}
	} 
	SAM.buildSuffixTree();
	memset(ans, -1, sizeof(ans));
	SAM.work();
	for(int i = 1; i <= q; ++ i) if(~ ans[i]) printf("%d\n", ans[i]);
}
posted @ 2017-08-27 09:35  Zeonfai  阅读(175)  评论(0编辑  收藏  举报