【HDU5687】Trie

题目大意:需要维护一个支持以下操作的数据结构:(1)支持插入一个字符串(2)支持删除所有前缀等于给定字符串的单词(3)查询该数据结构中是否存在一个以给定字符串为前缀的字符串

题解:由题目可知,需要维护数据结构就是一棵字典树。其中,支持插入和查找操作是字典树中的基本操作,即:在 Trie 的每个顶点处额外维护一个记录着有多少个字符串以该点到根节点组成的串为前缀。对于每次插入操作可知,修改的是 Trie 中的一条链,因此,在递归或迭代时,只需在到达的点直接加上 1 个贡献值即可。由以上分析可知,对于删除操作也是类似,只需查找给定的字符串结尾的顶点处的标记值,并在从根节点到该点的路径上将这个贡献值减去即可。最后,需要将这个点的子节点清空,表示删除了符合条件的字符串,即:使得这个点成为一个新节点。

递归版代码如下

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

struct trie {
	struct node {
		int cnt, go[26];
		node() {
			cnt = 0;
			memset(go, -1, sizeof(go));
		}
	};
	vector<node> t;
	int rt;
	trie() {
		rt = 0;
		t.emplace_back(node());
	}
	void insert(const string &s) {
		int now = rt;
		for (auto ch : s) {
			if (t[now].go[ch - 'a'] == -1) {
				t[now].go[ch - 'a'] = t.size();
				t.emplace_back(node());
			}
			now = t[now].go[ch - 'a'];
			t[now].cnt++;
		}
	} 
	int search(const string &s) {
		int now = rt;
		for (auto ch : s) {
			if (t[now].go[ch - 'a'] == -1) {
				return 0;
			}
			now = t[now].go[ch - 'a'];
		}
		return t[now].cnt;
	}
	void remove(const string &s, int val) {
		int now = rt;
		for (auto ch : s) {
			if (t[now].go[ch - 'a'] == -1) {
				return;
			}
			now = t[now].go[ch - 'a'];
			t[now].cnt -= val;
		}
		memset(t[now].go, -1, sizeof(t[now].go));
	}
};

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int n;
	cin >> n;
	trie t;
	while (n--) {
		string opt, s;
		cin >> opt >> s;
		if (opt[0] == 'i') {
			t.insert(s);
		} else if (opt[0] == 's') {
			cout << (t.search(s) ? "Yes" : "No") << endl;
		} else {
			t.remove(s, t.search(s));
		}
	}
	return 0;
}
posted @ 2018-12-18 00:29  shellpicker  阅读(164)  评论(0编辑  收藏  举报