voidinsert(string s){int len = s.length();int p =0;for(int i=0;i<len;i++){char c = s[i]-'a';if(!Trie[p][c]){
Trie[p][c]= k++;}
p = Trie[p][c];}
color[p]=1;}
查找操作
查找一个单词是否在字典树中,只要找到一条和单词吻合的链,且它的末尾被染色即可
boolsearch(string s){int len = s.length();int p =0;for(int i=0;i<len;i++){char c = s[i]-'a';if(!Trie[p][c])returnfalse;
p = Trie[p][c];}return color[p]==1;}
#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<string>#include<cmath>#include<iomanip>#include<queue>#include<stack>
using namespace std;typedeflonglong ll;constint MAXN =2e6+100;int Trie[MAXN][30];int k =1;int color[MAXN];int number[MAXN];voidinsert(string s){int len = s.length();int p =0;for(int i=0;i<len;i++){int c = s[i]-'a';if(!Trie[p][c]){
Trie[p][c]= k;
k++;}
number[p]++;
p = Trie[p][c];}
number[p]++;}intsearch(string s){int p =0;int len = s.length();for(int i=0;i<len;i++){int c = s[i]-'a';if(!Trie[p][c])return0;
p = Trie[p][c];}return number[p];}intmain(){
string s;while(true){getline(cin,s);if(s =="")break;insert(s);}while(cin>>s){
cout<<search(s)<<endl;}return0;}
在字典树上找即可,但有个小问题,正常应该开
1
e
6
×
26
1e6\times 26
1e6×26的数组,但是内存超了,这题开
1
e
5
×
26
1e5\times 26
1e5×26的数组也能过
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;constint N =1e5+5;structTrie{int ch[N][26];int color[N];int tot;Trie(){memset(ch,0,sizeof ch);memset(color,0,sizeof color);
tot =0;}voidInsert(string &s){int len = s.length();int p =0;for(int i=0;i<len;i++){int c = s[i]-'a';if(ch[p][c]==0){
ch[p][c]=++tot;}
p = ch[p][c];}
color[p]+=1;}intSerach(string &s){int len = s.length();int p =0;int ans =0;for(int i=0;i<len;i++){int x = s[i]-'a';
ans += color[p];if(ch[p][x]==0){return ans;}
p = ch[p][x];}
ans += color[p];return ans;}};
Trie trie;intmain(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);int n, m;
cin >> n >> m;for(int i=0;i<n;i++){
string s;
cin >> s;
trie.Insert(s);}for(int i=0;i<m;i++){
string s;
cin >> s;
cout << trie.Serach(s)<<'\n';}return0;}
这就是
01
t
r
i
e
01trie
01trie树的妙用,常规想法你必须
O
(
n
2
)
O(n^2)
O(n2),但是从二进制数的角度就可以优化到
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),把所有数都转化成
01
01
01串插入到trie树中,然后从根节点从高位到低位查询,因为就两种状态,一定是一棵二叉树,所以要么
0
0
0要么
1
1
1,为了让答案更大我们显然应该使得高位异或出来为
1
1
1,按照这个思路可以很容易求解
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;structTrie{int ch[3200000][2];int tot;Trie(){memset(ch,0,sizeof ch);
tot =0;}inlinevoidInsert(int n){int p =0;for(int i=31;i>=0;i--){int x =((n >> i)&1);if(!ch[p][x]){
ch[p][x]=++tot;}
p = ch[p][x];}}intSerach(int n){int p =0;int ans =0;for(int i=31;i>=0;i--){int x =((n >> i)&1);if(ch[p][x ^1]>0){
ans |=(1<< i);
p = ch[p][x ^1];}else{
p = ch[p][x];}}return ans;}};intmain(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);int n;
cin >> n;
vector<int>a(n);
Trie trie(n);for(int i=0;i<n;i++){
cin >> a[i];
trie.Insert(a[i]);}int ans =0;for(int i=0;i<n;i++){
ans =max(ans, trie.Serach(a[i]));}
cout << ans;return0;}
给定一个数组
a
a
a,给出
m
m
m次询问,每次询问
a
a
a数组中与给定数组中的异或结果最大的数
将
a
a
a建立
01
t
r
i
e
01trie
01trie树,每次查询的时候从根节点开始查找,假设当前为
x
x
x,如果
c
h
[
p
]
[
x
⊕
1
ch[p][x\oplus1
ch[p][x⊕1]存在说明答案的当前位是
x
⊕
1
x\oplus1
x⊕1;否则答案的当前位只能是
x
x
x
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;structTrie{int ch[3200005][2];int tot;Trie(){
tot =0;}voidInsert(ll n){int p =0;for(int i=31;i>=0;i--){int c =(n >> i &1);if(ch[p][c]==0){
ch[p][c]=++tot;}
p = ch[p][c];}}
ll Search(ll n){int p =0;
ll ans =0;for(int i=31;i>=0;i--){int c =(n >> i &1);if(ch[p][c ^1]>0){
p = ch[p][c ^1];
ans |=((c ^1)<< i);}else{
p = ch[p][c];
ans |=(c << i);}}return ans;}voidClear(int p){if(ch[p][0]>0)Clear(ch[p][0]);if(ch[p][1]>0)Clear(ch[p][1]);
ch[p][0]= ch[p][1]=0;
tot =0;}};
Trie trie;intmain(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);int t;
cin >> t;for(int kase=1;kase<=t;kase++){int n, m;
cin >> n >> m;for(int i=1;i<=n;i++){
ll u;
cin >> u;
trie.Insert(u);}
cout <<"Case #"<< kase <<":\n";for(int i=0;i<m;i++){
ll s;
cin >> s;
cout << trie.Search(s)<<'\n';}
trie.Clear(0);}return0;}