Trie(辞書ツリー)は、文字列の高速検索のためのマルチツリー構造です。Trieの各ノードにはいくつかの文字ポインターがあり、挿入または検索中に文字cがスキャンされると、現在のノードのc文字ポインターに続いて、ポインターが指すノードに移動します。
トライ構造は、時間と空間を交換する典型的なデータ構造です。空間の複雑さはO(NC)で、Nはノードの数、Cは文字セットのサイズを表します。
1つ:文字列処理の
例:プレフィックス統計
質問の意味:n個の文字列が与えられると、m個のクエリに対して毎回1つの文字列Tが要求され、s1〜snの文字列の数は彼のプレフィックスの
アイデアです。文字列を挿入する場合、挿入が完了する前に現在のノード++で終了する文字列の数と、T文字列を最初から最後まで要求します。
#include <bits/stdc++.h>
// trie 模板
using namespace std;
typedef long long ll;
const int MAXN = 1e6+7;
const int N = 5e5+7;
char str[MAXN];
int t[N][26],cnt[N],idx;//cnt数组保存以当前节点为结尾的字符串有几个
void insert(char *s)
{
int len = strlen(s);
int p = 0;
for(int i = 0;i < len;i ++){
if(!t[p][s[i]-'a']) t[p][s[i]-'a'] = ++idx;//这个idx就相当有我这个虚拟数组的分配的标号
p = t[p][s[i]-'a'];
}
cnt[p]++;//当前大小++
}
int query(char *s)
{
int len = strlen(s),p = 0,ans = 0;
for(int i = 0;i < len;i ++){
p = t[p][s[i]-'a'];
if(!p) break;
ans += cnt[p];
}
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
while(n--){
scanf("%s",str);
insert(str);
}
while(m--){
scanf("%s",str);
printf("%d\n",query(str));
}
return 0;
}
POJ3630
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 5e5+7;
string str[MAXN];
int trie[MAXN][17],idx,vis[MAXN];
bool insert(string s)
{
int p = 0,len = s.size();
for(int i = 0;i < len;i ++){
int ch = s[i]-'0';
if(!trie[p][ch]) trie[p][ch] = ++idx;
if(vis[p]) return true;
p = trie[p][ch];
}
vis[p] = 1;
return false;
}
bool cmp(string a,string b)
{
int lena = a.size(),lenb = b.size();
return lena < lenb;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
memset(vis,0,sizeof(vis));
memset(trie,0,sizeof(trie));
scanf("%d",&n);
for(int i = 1;i <= n;i ++){
cin>>str[i];
}
sort(str+1,str+1+n,cmp);
//for(int i = 1;i <= n;i ++) cout<<str[i]<<endl;
int flag = 0;
for(int i = 1;i <= n;i ++){
if(insert(str[i])){
flag = 1;
break;
}
}
if(flag)puts("NO");
else puts("YES");
}
return 0;
}
2:Trieは文字列だけでなく整数も操作できます。これは、10進数がバイナリの01文字列に変換できるため、整数のXOR操作を解くためによく使用されます。
例:最大XOR合計
質問の意味:n個の数値を指定して、それらの間のXORを組み合わせることによって取得できる最大値を見つけます。
アイデア:各数値を01バイナリ文字列と考え、trieを使用して各整数の01文字列を格納します。クエリを実行する場合、必要なのは排他的ORと最大値のみです。各ビットに対応する2進数は可能な限り異なります。したがって、クエリを実行する場合の最善の解決策は、現在のビット値とは異なる方向に進むことです。異なる方向が存在しない場合は、同じ方向に進みます。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5+7;
const int N = 5e5+7;
int trie[31*MAXN][2],idx;
int a[MAXN];
// 这道题就说明 trie 不仅可以 操作字符串 同时还可以对二进制状态下的01串进行操作
void insert(int x)
{
int p = 0;
for(int i = 30;i >= 0;i --){
int ch = x>>i & 1;
if(!trie[p][ch])
trie[p][ch] = ++idx;
p = trie[p][ch];
}
}
int search(int x){
int p = 0,sum = 0,cnt = 0;
for(int i = 30;i >= 0;i --){
int ch = x>>i & 1;// 二进制下的取每一位的方法
if(trie[p][!ch]){
p = trie[p][!ch];
sum += (1<<i)*(!ch);
}
else if(trie[p][ch]){
p = trie[p][ch];
sum += (1<<i)*ch;
}
else break;
}
return sum;
}
int main()
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i ++){
scanf("%d",&a[i]);
insert(a[i]);
}
int ans = 0;
for(int i = 1;i <= n;i ++){
ans=max(ans,search(a[i])^a[i]);
//printf("%d\n",search(a[i]));
}
printf("%d\n",ans);
return 0;
}
HDU5536のこの
質問は、trieの削除操作を使用します
。nの指定された数を見つけます。この質問の要件の
ため、(a [i] + a [j])^ a [k]の値が最大になるように3つの異なる数を見つけ
ます3つの数値を同じにすることはできないため、クエリを実行する前にトライからiとjを削除する必要があります。これは、フラグ配列マーク、挿入時の++、削除時の–を使用して実行できます。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e3+100;
int a[MAXN];
//因为要保证 三个数不能有相同的 因此这次要用到 trie树的删除结构
int trie[MAXN*31][2],idx,val[MAXN*31];//val数组保存存入的值
int flag[MAXN*31];
void insert(int x)
{
int p = 0;
for(int i = 30;i >= 0;i --){
int u = x>>i & 1;
if(!trie[p][u]) trie[p][u] = ++idx;
p = trie[p][u];
flag[p]++;//和后面的删除对着
}
val[p] = x;
}
void del(int x)//删除操作 不同就是 查询之前 先把 si,sj删除 然后再查询 查询完后 再插入si,sj
{
int p = 0;
for(int i = 30;i >= 0;i --){
int u = x>>i & 1;
p = trie[p][u];
flag[p]--;
}
}
int query(int x)
{
int p = 0;
for(int i = 30;i >= 0;i --){
int u = x>>i & 1;
p = (flag[trie[p][!u]]?trie[p][!u]:trie[p][u]);
}
return val[p]^x;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
memset(flag,0,sizeof(flag));
memset(val,0,sizeof(val));
memset(trie,0,sizeof(trie));
idx = 0;
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i ++){
scanf("%d",&a[i]);
insert(a[i]);
}
int ans = 0;
for(int i = 1;i < n;i ++){
for(int j = i+1;j <= n;j ++){
del(a[i]);
del(a[j]);
ans = max(ans,query(a[i]+a[j]));
insert(a[i]);
insert(a[j]);
}
}
printf("%d\n",ans);
}
return 0;
}