字典树
作者:互联网
概念:
字典树(TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。字典树主要包含两种操作,插入和查找。
模板:
字符串trie模板
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx;
char str[N];
//插入字符串
void insert(char str[]) {
int p = 0; // p从0开始,
for (int i = 0; str[i]; i++) {
int u = str[i] - 'a'; //转换成数字0-25
if (son[p][u] == 0)
son[p][u] = ++idx; //如果之前没出现过,就记录他的编号,从开头开始,如果之前在一样的位置,出翔了一样的字母
//就不用新的编号,沿用之前的编号。如果之前,在对应的位置,就记录新的编号。一样的位置一样的字母就是一样的编号,每一种编号仅代表对应位置的对应字母,其中一个不一样,编号一定是不一样的
p = son[p][u]; // p在这里还担任指针的作用
}
cnt[p]++; //对应的编号(最后一个单字符)+1
}
//查询字符串
int ask(char str[]) {
int p = 0;
for (int i = 0; str[i]; i++) {
int u = str[i] - 'a';
if (son[p][u] == 0)
return 0; //当对应位置对应的字母编号是0的话,就说明没找到
p = son[p][u]; //指针往下找
}
return cnt[p]; //返回对应编号出现的次数
}
int main() {
int n;
scanf("%d", &n);
while (n--) {
char op[2];
scanf("%s%s", op, str);
if (op[0] == 'I') {
insert(str);
} else {
printf("%d\n", ask(str));
}
}
return 0;
}
01字典树模板
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 100010;
int a[N], son[N * 31][2], idx;
void build(int x) { //建树
int p = 0;
for (int i = 30; i >= 0; i--) {
int u = x >> i & 1; //取二进制的首位,
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
}
int ask(int x) {
int p = 0, ans = 0;
for (int i = 30; i >= 0; i--) {
int u = x >> i & 1;
if (son[p][!u]) {
p = son[p][!u];
ans =ans * 2 + !u; //这里类似于二进制转化成十进制,就是左移后奖赏你想要的末尾二进制数
} else {
p = son[p][u];
ans = ans * 2 + u;
}
}
return ans;
}
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int ans = 0;
for (int i = 0; i < n; i++) {
build(a[i]);
int t = ask(a[i]);
ans = max(ans, t ^ a[i]);
}
printf("%d\n", ans);
return 0;
}
例题:
于是他错误的点名开始了
wudima的XOR小游戏
View Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
int a[N], son[N * 31][2], idx;
void build(int x) {
int p = 0;
for (int i = 30; i >= 0; i--) {
int u = x >> i & 1;
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
}
int ask(int x) {
int p = 0, ans = 0;
for (int i = 30; i >= 0; i--) {
int u = (x >> i) & 1;
if (son[p][u]) {
p = son[p][u];
} else {
p = son[p][!u];
ans |= (1 << i);
}
}
return ans;
}
int dfs(int l, int r, int now) {
if (l > r || now < 0) return 0;
int zero = 0;
int mid = l - 1;
for (int i = l; i <= r; i++) {
if ((a[i] >> now) & 1) {
mid = i - 1;
break;
} else {
zero++;
}
}
if (zero % 2 == 0) {
return max(dfs(l, mid, now - 1), dfs(mid + 1, r, now - 1));
} else {
int ans = 2e9;
for (int i = l; i <= mid; i++) {
build(a[i]);
}
for (int i = mid + 1; i <= r; i++) {
int t = ask(a[i]);
ans = min(ans, t);
}
return ans;
}
}
signed main() {
int n;
cin >> n;
for (int i = 1; i <= 2 * n; i++) {
cin >> a[i];
}
sort(a + 1, a + n * 2 + 1);
int res = dfs(1, 2 * n, 30);
cout << res;
return 0;
}
Trie字符串统计
最大异或对
最长异或值路径
牛异或
D. Binary Spiders
View Code
#include <bits/stdc++.h>
#include<iostream>
using namespace std;
const int N = 3e5 + 10;
int a[N];
map<int, int> id;
map<int, vector<int> > mp;
vector<int> res;
int son[N * 31][2], idx;
int n, k;
int get(int x) {
int cnt = 0;
while (x) {
x >>= 1;
cnt++;
}
return cnt;
}
void insert(int x) {
int p = 0;
for (int i = 30; i >= 0; i--) {
int u = (x >> i) & 1;
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
}
int query(int x) {
int p = 0, ans = 0;
for (int i = 30; i >= 0; i--) {
int u = x >> i & 1;
if (son[p][!u]) {
p = son[p][!u];
ans = ans * 2 + !u;
} else {
p = son[p][u];
ans = ans * 2 + u;
}
}
return ans;
}
int main() {
cin >> n >> k;
int m = get(k);
for (int i = 1; i <= n; i++) {
cin >> a[i];
int x = a[i] >> m;
mp[x].push_back(a[i]);
id[a[i]] = i;
}
if (k == 0) {
cout << n << endl;
for (int i = 1; i <= n; i++) {
cout << i << " ";
}
return 0;
} else {
for (auto it : mp) {
memset(son, 0, 4 * 2 * (idx + 4));
idx = 0;
vector<int> p = it.second;
int l = -1, r = -1;
int dex = -1;
for (int i = 0; i < p.size(); i++) {
int now = p[i];
dex = id[now];
insert(now);
int t = query(now);
if ((t ^ now) >= k) {
l = id[now];
r = id[t];
break;
}
}
if (l!=-1 && r!=-1) {
res.push_back(l);
res.push_back(r);
} else if (dex > 0) {
res.push_back(dex);
}
}
if (res.size() <= 1) {
puts("-1");
} else {
printf("%d\n", res.size());
for (int i = 0; i < res.size(); i++) {
printf("%d ", res[i]);
}
}
}
}
Ex - Multiply or Divide by 2
View Code
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int tr[N * 31][2];
int cnta[N * 31], cntb[N * 31];
bool flag = 1;
int n;
int idx;
int ans;
int count(int x) {
int res = 0;
while (x) x /= 2, res++;
return res;
}
void dfs(int u) {
if (tr[u][0]) {
ans += abs(cnta[tr[u][0]] - cntb[tr[u][0]]);
dfs(tr[u][0]);
}
if (tr[u][1]) {
if (cntb[tr[u][1]] > cnta[tr[u][1]]) {
flag = 0;
return;
}
ans += abs(cnta[tr[u][1]] - cntb[tr[u][1]]);
dfs(tr[u][1]);
}
}
signed main() {
cin >> n;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
int p = 0;
for (int j = count(x); j >= 0; j--) {
int u = (x >> j) & 1;
if (!tr[p][u]) tr[p][u] = ++idx;
p = tr[p][u];
cnta[p]++;
}
}
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
int p = 0;
for (int j = count(x); j >= 0; j--) {
int u = (x >> j) & 1;
if (!tr[p][u]) tr[p][u] = ++idx;
p = tr[p][u];
cntb[p]++;
}
}
dfs(0);
if (flag)
cout << ans << endl;
else
cout << "-1" << endl;
}
D2. 388535 (Hard Version)
标签:int,tr,son,++,ans,include,字典 来源: https://www.cnblogs.com/OverThink/p/16545617.html