trie(字典树)—— 模板

1.trie

这个是插入字符串形成的树。

题目链接

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1000000+10;
int son[N][26], cou[N], idx = 0;
char str[N];
void insert() {
	int p = 0;
	for(int i=0; str[i]; i++) {
		int &s = son[p][str[i]-'a'];
		if(!s) s = ++idx;
		p = s;
	}
	cou[p]++;
}
int qury() {
	int p = 0, sum = 0;
	for(int i=0; str[i]; i++) {
		int &s = son[p][str[i]-'a'];
		if(!s)	break;
		p = s;
		sum += cou[p];
	}
	return sum;
}
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for(int i=0; i<n; i++) {
		scanf("%s", str);
		insert();
	}
	for(int i=0; i<m; i++) {
		scanf("%s", str);
		printf("%d\n", qury());
	}
//	for(int i=0; i<20; i++) {
//		for(int j=0; j<26; j++) {
//			cout << son[i][j] << ' ';
//		}
//		cout << endl;
//	}
//打印son数组
	return 0;
}

刚开始看到son数组有点懵,但后面可以把son数组打印出来看看就可以发现s[1][i] = k; 树的第一层有第i个字母,它连接的字符串的下一个字母是在第k行
在这里插入图片描述
cou[i]数组表示的是以第i个字符结尾的的字符串的个数
son表中每一个数字都是不同的
insert()函数表示向树里插入str字符串(第一个字符在第一层…
qury()函数表示查询在已有的树中,str字符串前缀的个数sum


例题
最大异或对

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010, M = 3110000;
int son[M][2], cou[M], idx, s[N];
void insert(int x) {
	int p = 0;
	for(int i=30; i>=0; i--) {
		int &n = son[p][x>>i & 1];
		if(!n) n = ++idx;
		p = n;
	} 
//	cou[p] = x;
}

int qury(int x) {
	int p = 0, sum = 0; 
	for(int i=30; i>=0; i--) {
		int m = x>>i & 1;
		if(son[p][!m]) {
			sum += 1<<i;
			p = son[p][!m];
		}
		else	p = son[p][m];
	}
//	return cou[p];
	return sum;
}
int main() {
	int a;
	scanf("%d", &a);
	for(int i=0; i<a; i++) {
		scanf("%d", &s[i]);
		insert(s[i]);
	}
//	for(int i=0; i<100; i++) {
//		for(int j=0; j<2; j++) {
//			cout << son[i][j] << ' ';
//		}
//		cout << endl;
//	} 
	int maxn = 0;
	for(int i=0; i<a; i++) {
//		maxn = max(maxn, s[i]^qury(s[i]));
		maxn = max(maxn, qury(s[i]));
	}
	cout << maxn << endl;
	return 0;
}

insert()用来构建trie,son数组用来保留数字的二进制参考模板
qury()用来找异或的最大值。
原理:
异或 不同为1,从最高位开始找不同,有不同的则向下找,没有就找相同的向下找。


最长异或值路径
这题和上一题还是有联系的
题目给的是一棵树,我们要从树上找两个节点路径权值异或最大
我们可以理解成从两个节点到根节点再做异或(图)
在这里插入图片描述
从a到b的异或值 == 从a到root ^ 从b到root的值。因为从root到c的值异或了两次(a^a = 0)。
现在我们要算出各个节点到根节点的异或值。
我们用**数组来模拟邻接表有兴趣可以去上一篇博客看看 **去存储树,再dfs找到a[i](第i个节点到根节点的异或值)最后从所有a[i]中选两个节点找异或的最大值(上一题)。

#include<iostream>
#include<cstdio>
#include<cstring> 
using namespace std;
const int N = 100010, M = 3000000;
int son[M][2], idx = 0, a[N];
struct e {
	int to, w, next;
}edge[2 * N];
int head[N], cnt = 0;
void add(int u, int v, int w) {
	edge[cnt].to = v, edge[cnt].w = w, edge[cnt].next = head[u];
	head[u] = cnt++;
}
void dfs(int u, int father, int sum) {
	a[u] = sum;
	for(int i=head[u]; ~i; i=edge[i].next) {
		int q = edge[i].to;
		if(q != father) {
			dfs(q, u, edge[i].w^sum);
		}
	}
}
void insert(int x) {
	int p = 0;
	for(int i=30; ~i; i--) {
		int &s = son[p][x>>i & 1];
		if(!s)	s = ++idx;
		p = s;
	}
}
int qury(int x) {
	int p = 0, sum = 0;
	for(int i=30; ~i; i--) {
		int s = x>>i & 1;
		if(son[p][!s]) {
			sum += 1<<i;
			p = son[p][!s];
		}
		else {
			p = son[p][s];
		}
	}
	return sum;
}
int main() {
	memset(head, -1, sizeof(head));
	int n, u, v, w, maxn = 0;
	cin >> n;
	for(int i=0; i<n-1; i++) {
		cin >> u >> v >> w;
		add(u, v, w);
		add(v, u, w);
	}
	dfs(0, -1, 0);
	for(int i=0; i<n; i++) {
		insert(a[i]);
	}
	for(int i=0; i<n; i++) {
		maxn = max(maxn, qury(a[i]));
	}
	cout << maxn << endl;
	return 0;
}

可以去这里看看,这里有题目。滑稽

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值