トライの紹介サンプルの質問の概要

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

おすすめ

転載: blog.csdn.net/weixin_45672411/article/details/107565836