字典树Trie(专项复习)

一.P8306 【模板】字典树

 

题目思路:字典树的板子题,熟练写出insert函数(建树),以及query函数(查询)即可.

代码实现:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define N 3000005
#define P 131
ll f1[N];
string s;
char ss[N];
ll n, m, num, ans, t, id;
int cnt[N],ch[N][126];
typedef pair<char, ll>pii;
void clear()
{
	for (int i = 0; i <= id; i++) {
		cnt[i] = 0;
		for (int j = 0; j <= 126; j++) {
			ch[i][j] = 0;
		}
	}
	id = 0;
}
void insert(string s) {
	int p=0;
	for (int i = 0; i <= s.size(); i++) {
		int j = (int)s[i];
		if (!ch[p][j]) ch[p][j] = ++id;
		p = ch[p][j];
		cnt[p]++;
	}
}
ll find(string s) {
	int p = 0;
	for (int i = 0; i < s.size(); i++) {
		int j = (int)s[i];
		if (!ch[p][j]) return 0;
		p = ch[p][j];
	}
	return cnt[p];
}
int main()
{
	cin >> t;
	while (t--) {
		clear();
		cin >> n >> m;
		for (int i = 1; i <= n; i++) {
			cin >> s;
			insert(s);
		}
		for (int i = 1; i <= m; i++) {
			cin >> s;
			cout << find(s) << endl;
		}
	}
	return 0;
}

二.P1481 魔族密码

 

题目思路:因为是记录最长词链,我们只要在query函数中,使ans+=cnt[p],即将每个节点的单词个数进行累加即可,insert函数不变.

代码实现:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define N 3000005
#define P 131
char s[N];
int ch[N][27],cnt[N];
int n, m, k, num, sum;
void insert(char s[])
{
	int p = 0;
	for (int i = 0; s[i]; i++) {
		int q = s[i] - 'a' + 1;
		if (!ch[p][q]) ch[p][q] = ++num;
		p = ch[p][q];
	}
	cnt[p]++;
}
int query(char s[]) {
	int p = 0, ans = 0;
	for (int i = 0; s[i]; i++) {
		int q = s[i] - 'a' + 1;
		if (!ch[p][q]) return 0;
		p = ch[p][q];
		ans += cnt[p];
	}
	return ans;
}
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> s;
		insert(s);
		sum = max(query(s), sum);
	}
	cout << sum << endl;
	return 0;
}

三.P2580 于是他错误的点名开始了

 

题目思路:先把所有的人名字存起来,通过insert函数,这样可以建立从名字到数的映射,标记为1,然后扫一遍,如果为1,输出OK,同时将cnt数组++,如果遇到>1,输出REPEAT,如果为0,说明没有,输出WRONG

代码实现:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define N 3000005
#define P 131
char s[N];
int ch[N][27],cnt[N];
int n, m, k, num, sum;
void insert(char s[])
{
	int p = 0;
	for (int i = 0; s[i]; i++) {
		int q = s[i] - 'a' + 1;
		if (!ch[p][q]) ch[p][q] = ++num;
		p = ch[p][q];
	}
	cnt[p]=1;
}
int query(char s[]) {
	int p = 0, ans = 0;
	for (int i = 0; s[i]; i++) {
		int q = s[i] - 'a' + 1;
		if (!ch[p][q]) return 0;
		p = ch[p][q];
	}
	if (!cnt[p]) return 0;
	if (cnt[p] == 1) {
		cnt[p]++;
		return 1;
	}
	return 2;
}
int main()
{
	cin >> n;
	memset(cnt, 0, sizeof(cnt));
	for (int i = 1; i <= n; i++) {
		cin >> s;
		insert(s);
	}
	cin >> m;
	for (int i = 1; i <= m; i++) {
		cin >> s;
		int k = query(s);
		if (k == 0)
			cout << "WRONG" << endl;
		if (k == 1)
			cout << "OK" << endl;
		if (k == 2)
			cout << "REPEAT" << endl;
	}
	return 0;
}

四.P2922 [USACO08DEC] Secret Message G

 

题目思路:和魔族密码这道题有点像,但是我们要维护两个数组,即一个ans数组记录经过该节点的次数,另一个cnt数组记录以该节点结束的次数,在query时,不断累加ans数组的值,最后再sum - cnt[p] + ans[p](因为在最后时应该把以当前结束的次数去掉).

代码实现:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define N 3000005
#define P 131
ll s[N];
ll ch[N][3],cnt[N],ans[N];
int n, m, k, num=1, sum;
void insert(ll s[])
{
	ll p = 1;
	for (int i = 1; i <= k; i++) {
		ll q = s[i];
		if (!ch[p][q]) ch[p][q] = ++num;
		p = ch[p][q];
		ans[p]++;
	}
	cnt[p]++;
}
int query(ll s[]) {
	ll p = 1;
	sum = 0;
	for (int i = 1; i <= k; i++) {
		ll q = s[i];
		if (!ch[p][q]) return sum;
		p = ch[p][q];
		sum += cnt[p];
	}
	return sum - cnt[p] + ans[p];
}
int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> k;
		for (int j = 1; j <= k; j++) cin >> s[j];
		insert(s);
	}
	for (int i = 1; i <= m; i++) {
		cin >> k;
		for (int j = 1; j <= k; j++) cin >> s[j];
		cout << query(s) << endl;
	}
	return 0;
}

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值