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;
}