Luogu P2922 [USACO08DEC]秘密消息Secret Message 字典树 Trie树

本来想找\(01Trie\)的结果找到了一堆字典树水题。。。算了算了当水个提交量好了。

直接插入模式串,维护一个\(Trie\)树的子树\(sum\)大小,求解每一个文本串匹配时走过的链上匹配数和终点处的子树大小之和。

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

int top, sta[10010];
int n, m, l, s[10010], max_size;
int ch[500010][2], sz[500010], sum[500010];

void push_up (int p) {
	sz[p] = sum[p];
	if (ch[p][0]) sz[p] += sz[ch[p][0]];
	if (ch[p][1]) sz[p] += sz[ch[p][1]];
}

void add_str () {
	int now = 0;
	sta[top = 1] = 0;
	for (int i = 1; i <= l; ++i) {
		if (!ch[now][s[i]]) {
			ch[now][s[i]] = ++max_size;
		}
		// printf ("ch[%d][%d] = %d\n", now, s[i], ch[now][s[i]]);
		now = ch[now][s[i]];
		sta[++top] = now;
	}
	sz[now]++;
	sum[now]++;
	while (top > 0) push_up (sta[top--]);
}

int get_str () {
	int now = 0, ans = 0;
	for (int i = 1; i <= l; ++i) {
		if (!ch[now][s[i]]) {
			return ans;
		}
		// printf ("now = %d, sum[now] = %d sz[now] = %d\n", now, sum[now], sz[now]);
		now = ch[now][s[i]];
		ans += sum[now];
	}
	// printf ("now = %d\n", now);
	ans += sz[now] - sum[now];
	return ans;
}

int main () {
	cin >> m >> n;
	for (int i = 1; i <= m; ++i) {
		scanf ("%d", &l);
		for (int j = 1; j <= l; ++j) {
			scanf ("%d", &s[j]);
		}
		add_str ();
	}
	for (int i = 1; i <= n; ++i) {
		scanf ("%d", &l);
		for (int j = 1; j <= l; ++j) {
			scanf ("%d", &s[j]);
		}
		cout << get_str () << endl;
	}
}

posted @ 2019-02-27 08:11  maomao9173  阅读(187)  评论(0编辑  收藏  举报