ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF710F String Set Queries(AC自动机+二进制分组)

2020-07-07 11:08:08  阅读:227  来源: 互联网

标签:rt AC Set String int top trie ch fail


题意

维护一个集合,满足下面三种操作:

加字符串

删字符串

查询集合中的所有字符串在给出的模板串中出现的次数

强制在线

Analysis

如果不强制在线我们就可以用cdq来做,但这道糟糕的题目它强制在线。。。

首先我们发现对于加和删我们可以维护两个AC自动机,然后答案相减即可。

现在的问题在于怎么往一个AC自动机中插入一个串然后维护AC自动机。

二进制分组的思想就是把每\(2^i\)个修改放在一个数据结构里维护,然后再类似2048一样合并,最后暴力重构。

比如:\(31=16+8+4+2+1\),又多了一个变成\(32=16+8+4+2+1+1=16+8+4+2+2=16+8+4+4=16+8+8=16+16=32\)。

查询时就在这log个里面查,时间复杂度是\(O(n\log{n})\)级别的很好理解。

关键是修改的复杂度。

可以发现第\(k\)个修改的暴力重构的大小即为\(lowbit(k)\),设重构的复杂度是\(O(f(size))\)。

则修改复杂度为\(\sum_{i=1}^n O(f(lowbit(k)))=\sum_{i=1}^{\log n} O(\frac{n}{2^{i+1}} * f(2^i)) \le \sum_{i=1}^{\log n} O(f(i))=O(f(n)\log{n})\)。

这道题就迎刃而解了。注意为了合并要维护一个trie树再维护一个AC自动机。

// CF710F String Set Queries
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int LEN = 300010;
int n;
struct ACAM{
	int ch[LEN][26], trie[LEN][26], fail[LEN], sum[LEN], end[LEN];
	int sz[21], rt[21];
	int tot, top;
	ACAM() {
		tot = top = 0;
	}
	void get_fail(int id) {
		queue<int> q;
		while (!q.empty()) q.pop();
		int p = rt[id];
		fail[p] = 0;
		for (int i = 0; i < 26; i++) {
			if (trie[p][i]) {
				ch[p][i] = trie[p][i];
				fail[ch[p][i]] = p;
				q.push(ch[p][i]);
			} else {
				ch[p][i] = p;
			}
		}
		while (!q.empty()) {
			p = q.front();
			q.pop();
			sum[p] = end[p] + sum[fail[p]];
			for (int i = 0; i < 26; i++) {
				if (trie[p][i]) {
					ch[p][i] = trie[p][i];
					fail[ch[p][i]] = ch[fail[p]][i];
					q.push(ch[p][i]);
				} else {
					ch[p][i] = ch[fail[p]][i];
				}
			}
		}
	}
	int merge(int x, int y) {
		if (!x || !y) return x | y;
		end[x] += end[y];
		for (int i = 0; i < 26; i++) {
			trie[x][i] = merge(trie[x][i], trie[y][i]); 
		}
		return x;
	}
	void insert(char *s) {
		rt[++top] = ++tot;
		sz[top] = 1;
		int len = strlen(s + 1);
		int p = rt[top];
		for (int i = 1; i <= len; i++) {
			p = trie[p][s[i] - 'a'] = ++tot;
		}
		end[p]++;
		while (top > 1 && sz[top] == sz[top - 1]) {
			rt[top - 1] = merge(rt[top - 1], rt[top]);
			sz[top - 1] += sz[top];
			sz[top] = rt[top] = 0;
			top--;
		}
		get_fail(top);
	}
	int ask(char *s) {
		int len = strlen(s + 1);
		int ret = 0;
		for (int i = 1; i <= top; i++) {
			int p = rt[i];
			for (int j = 1; j <= len; j++) {
				p = ch[p][s[j] - 'a'];
				ret += sum[p];
			}
		}
		return ret;
	}
}tr1, tr2;
int main() {
	scanf("%d", &n);
	while (n--) {
		int opt;
		char s[LEN];
		scanf("%d%s", &opt, s + 1);
		if (opt == 1) {
			tr1.insert(s);
		} else if (opt == 2) {
			tr2.insert(s);
		} else {
			printf("%d\n", tr1.ask(s) - tr2.ask(s));
			fflush(stdout);
		}
	}
	return 0;
}

标签:rt,AC,Set,String,int,top,trie,ch,fail
来源: https://www.cnblogs.com/zcr-blog/p/13259551.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有