具体原理:刘汝佳《算法竞赛入门经典训练指南》P208
作用:字典树又叫单词查找树(Trie)或前缀树,是一个实现字符串。你可以在O(m)(m为所给单词的长度)时间内判断出该单词是否属于字典。
代码模板:
#include<cstdio>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<numeric>
#include<cctype>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<list>
#include<set>
#include<map>
using namespace std;
#define N 300000+5
#define MAX 26
typedef long long ll;
const int maxnode=400000+100;//预计字典树最大节点数目
const int sigma_size=26; //每个节点的最多儿子数
struct Trie
{
int ch[maxnode][sigma_size];//ch[i][j]==k表示第i个节点的第j个儿子是节点k
int val[maxnode];//val[i]==x表示第i个节点的权值为x
int sum[maxnode];//sum[i]==x表示第i个节点的次数为x,便于删除
int sz;//字典树一共有sz个节点,从0到sz-1标号
//初始化
void clear()
{
sz=1;
memset(ch[0],0,sizeof(ch[0]));//ch值为0表示没有儿子
memset(sum,0,sizeof(sum));
}
//在字典树中插入单词s,但是如果已经存在s单词会重复插入且覆盖权值
//所以insert前需要判断一下是否已经存在s单词了
void insert(string s)
{
int u=0,n=s.length();
for(int i=0;i<n;i++)///建立字典树
{
int id=s[i]-'a';
if(ch[u][id]==0)//无该儿子
{
ch[u][id]=sz;
memset(ch[sz],0,sizeof(ch[sz]));
val[sz++]=0;
}
u=ch[u][id];
sum[u]++;
}
val[u]=n;
}
//在字典树中查找单词s
bool find1(string s)
{
int n=s.length(),u=0;
for(int i=0;i<n;i++)
{
int id=s[i]-'a';
if(ch[u][id]==0)
return false;
u=ch[u][id];
}
return val[u];
}
int find2(string s)///查找前缀为s的个数
{
int n=s.length(),u=0;
for(int i=0;i<n;i++)
{
int id=s[i]-'a';
if(ch[u][id]==0)
return 0;
u=ch[u][id];
}
return sum[u];
}
void del(string s,int cnt) //删除前缀s的所有单词
{
int n=s.length(),u=0;
for(int i=0;i<n;i++)
{
int id=s[i]-'a';
if(ch[u][id]==0)
return ;
u=ch[u][id];
sum[u]-=cnt;
}
for(int i=0;i<26;i++)
ch[u][i]=0;
}
};
Trie trie;
int main()
{
int n;
while(scanf("%d",&n)!=-1)
{
trie.clear();
for(int i=1;i<=n;i++)
{
string s1,s2;
cin>>s1>>s2;
if(s1[0]=='i')
{
trie.insert(s2);
}
else if(s1[0]=='d')
{
trie.del(s2,trie.find2(s2));
}
else
{
if(trie.find2(s2)!=0)
{
printf("Yes\n");
}
else
printf("No\n");
}
}
}
return 0;
}
动态申请
#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int MAXN = 1e2 + 50;
const int MAXM = 1e5 + 50;
const int MOD = 1e9 + 7;
struct node
{
int v;
node* nxt[26];
node()
{
v = 0;
memset(nxt, NULL, sizeof(nxt));
}
};
void trie_insert(node* root, char* word)
{
node* now = root;
int len = strlen(word);
for (int i = 0; i < len; i++)
{
int id = word[i] - 'a';
if (now->nxt[id] == NULL)
now->nxt[id] = new node();
now = now->nxt[id];
now->v++;
}
}
void trie_delete(node* root, char* word)
{
node* now = root;
int len = strlen(word), del;
for (int i = 0; i < len; i++)
{
int id = word[i] - 'a';
if (now->nxt[id] == NULL)
return;
now = now->nxt[id];
del = now->v;
}
now = root;
for (int i = 0; i < len; i++)
{
int id = word[i] - 'a';
if (now->nxt[id] == NULL)
return;
if (i == len - 1)
{
free(now->nxt[id]);
now->nxt[id] = NULL;
return;
}
now = now->nxt[id];
now->v -= del;
}
}
bool trie_query(node* root, char* word)
{
node* now = root;
int len = strlen(word);
int ans = INF;
for (int i = 0; i < len; i++)
{
int id = word[i] - 'a';
if (now->nxt[id] == NULL)
return false;
now = now->nxt[id];
}
return now->v != 0;
}
int main()
{
int n;
scanf("%d", &n);
char op[35], word[35];
node* root = new node();
while (n--)
{
scanf("%s%s", op, word);
if (strcmp(op, "insert") == 0)
trie_insert(root, word);
else if (strcmp(op, "delete") == 0)
trie_delete(root, word);
else
printf("%s\n", trie_query(root, word) ? "Yes" : "No");
}
return 0;
}
01字典树
数组:
#include<cstdio>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<numeric>
#include<cctype>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<list>
#include<set>
#include<map>
using namespace std;
#define N 10000+5
typedef long long ll;
const int maxnode=1500000+100;//预计字典树最大节点数目
const int sigma_size=35; //每个节点的最多儿子数
struct Trie
{
int ch[maxnode][sigma_size];//ch[i][j]==k表示第i个节点的第j个儿子是节点k
int val[maxnode];//val[i]==x表示第i个节点的权值为x
int sum[maxnode];//sum[i]==x表示第i个节点的次数为x,便于删除
int sz;//字典树一共有sz个节点,从0到sz-1标号
//初始化
void clear()
{
sz=1;
memset(ch[0],0,sizeof(ch[0]));//ch值为0表示没有儿子
memset(sum,0,sizeof(sum));
}
//在字典树中插入单词s,但是如果已经存在s单词会重复插入且覆盖权值
//所以insert前需要判断一下是否已经存在s单词了
void insert(int num)
{
int u=0;
for(int i=31;i>=0;i--)///建立字典树
{
int id=((num>>i)&1);
if(ch[u][id]==0)//无该儿子
{
ch[u][id]=sz;
memset(ch[sz],0,sizeof(ch[sz]));
val[sz++]=0;
}
u=ch[u][id];
sum[u]++;
}
//val[u]=n;
}
int find3(int num1,int num2)
{
int u=0;
int ans=0;
for(int i=31;i>=0;i--)
{
int t1=((num1>>i)&1);
int t2=((num2>>i)&1);
if(t1)
{
if(t2)
{
if(ch[u][1])
ans+=sum[ch[u][1]];
u=ch[u][0] ;
}
else
{
u=ch[u][1];
}
}
else
{
if(t2)
{
if(ch[u][0])
ans+=sum[ch[u][0]];
u=ch[u][1];
}
else
u=ch[u][0];
}
if(u==0) break;
}
return ans;
}
void del(int num,int cnt)
{
int u=0;
for(int i=31;i>=0;i--)
{
int id=((num>>i)&1);
if(ch[u][id]==0)
return ;
u=ch[u][id];
sum[u]-=cnt;
}
}
};
Trie trie;
int main()
{
int n;
scanf("%d",&n);
trie.clear();
for(int i=1;i<=n;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
int x;
scanf("%d",&x);
trie.insert(x);
}
else if(op==2)
{
int x;
scanf("%d",&x);
trie.del(x,1);
}
else
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",trie.find3(x,y));
}
}
return 0;
}
动态开点
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#define rt return
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define db(x) cout<<"== [ "<<x<<" ] =="<<endl;
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
inline void getInt(int* p);
const int maxn=1000010;
const int inf=0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
struct node
{
int num;
node *Next[2];
node()
{
num=0;
Next[0]=Next[1]=nullptr;
}
};
void Add(node *head , int num)
{
node *p=head;
for(int i=31;i>=0;i--)
{
int k=((num>>i)&1);
if(p->Next[k]== nullptr)
{
node *q =new node();
p->Next[k]= q;
}
p = p->Next[k];
p->num++;
}
// p->num=num;
}
void Del(node *head ,int num)
{
node *p=head;
for(int i=31;i>=0;i--)
{
int k=((num>>i)&1);
if(p->Next[k]==NULL)
{
node * q=new node();
p->Next[k] = q;
}
p = p->Next[k];
p->num--;
}
}
int Find(node *head, int num)
{
node *p = head;
for(int i=31;i>=0;i--)
{
int k=((num>>i)&1);
if(p->Next[k^1]!=NULL)
{
p = p->Next[k^1];
}else
{
p = p->Next[k];
}
}
return p->num;
}
void query(node * root,int x,int y)
{
node *p = root;
int res=0;
for(int i=31;i>=0;--i)
{
int tx=(x&(1<<i));
int tl=(y&(1<<i));
if(tx)
{
if(tl)
{
if(p->Next[1])
res+=p->Next[1]->num;
p=p->Next[0];
}else
{
p=p->Next[1];
}
}else
{
if(tl)
{
if(p->Next[0])
res+=p->Next[0]->num;
p=p->Next[1];
}else
{
p=p->Next[0];
}
}
if(p==nullptr)
break;//
}
printf("%d\n",res);
}
int n;
int main()
{
gg(n);
node *head = new node();
repd(i,1,n)
{
int op,x,y;
gg(op);
if(op==1)
{
gg(x);
Add(head,x);
}else if(op==2)
{
gg(x);
Del(head,x);
}else
{
gg(x),gg(y);
query(head,x,y);
}
}
return 0;
}
inline void getInt(int* p) {
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
}
else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}
经典例题:
HDU 1251 统计难题 字典树简单应用(找出所有以字符串s为前缀的单词个数)
Uva1401 Remember the Word 字典树简单应用(求一个字符串能有多少种方式通过字典中的单词构成)
HDU 1671 Phone List 字典树 (多种做法:问你字典中是否有一个字符串是其他字符串的前缀)
HDU 1247 Hat’s Words( 字典树Trie):单词匹配
异或(两题一样,推荐第二道)
CH 1602 The XOR Largest Pair 字典树+异或
NBUT-1597 Find MaxXorSum 经典字典树求异或最大值(数据量大)
HDU – 5536 Chip Factory 字典树的删除
CodeForces – 633C Spy Syndrome 2 ( 字典树+dfs)
POJ 3764 The xor-longest Path dfs+字典树求最大异或