字典树模板
const int maxn=2e6+5;
int tree[maxn][55]; //tree[i][j]表示节点i的第j个儿子的节点编号
bool flagg[maxn]; //表示以该节点结尾的是一个单词
int tot; //总结点数
void insert_(char *str)
{
int len=strlen(str);
int root=0;
for(int i=0;i<len;i++){
int id=str[i]-'a';
if(!tree[root][id])tree[root][id]=++tot;
root=tree[root][id];
}
flagg[root]=true;
}
bool find_(char *str)
{
int len=strlen(str);
int root=0;
for(int i=0;i<len;i++)
{
int id=str[i]-'a';
if(!tree[root][id])return false;
root=tree[root][id];
}
return true;
}
void init()
{
for(int i=0;i<=tot;i++)
{
flagg[i]=false;
for(int j=0;j<10;j++)
tree[i][j]=0;
}
tot=0;
}
例题·
1、HUD2072
题意:统计一篇文章里不同单词出现次数。
思路:字典树储存,进行多次查找和插入。用flagg判断是否为单词。
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define ll long long
#define MOD 998244353
#define INF 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int maxn=2e6+5;
int tree[maxn][30]; //tree[i][j]表示节点i的第j个儿子的节点编号
bool flagg[maxn]; //表示以该节点结尾的是一个单词
int sum[maxn]={0};
int tot; //总结点数
void insert_(char *str,int len)
{
int root=0;
for(int i=0;i<len;i++){
int id=str[i]-'a';
if(!tree[root][id])tree[root][id]=++tot;
root=tree[root][id];
}
flagg[root]=true;
}
bool find_(char *str,int len)
{
int root=0;
string ans="";
for(int i=0;i<len;i++)
{
int id=str[i]-'a';
ans+=str[i];
if(!tree[root][id])return false;
root=tree[root][id];
}
if(flagg[root]==true){
return true;
}else{
return false;
}
}
void init()
{
for(int i=0;i<=tot;i++)
{
flagg[i]=false;
for(int j=0;j<10;j++)
tree[i][j]=0;
}
tot=0;
}
string s;
char s1[105];
int main()
{
while(getline(cin,s))
{
int ans=0,k=0,d=0;
if(s[0]=='#')break;
for(int i=0;i<s.size();i++){
if(s[i]==' '&&k==1){
if(!find_(s1,d)){
ans++;
insert_(s1,d);
}
k=0;
d=0;
}else{
if(s[i]==' ')continue;
s1[d++]=s[i];
k=1;
}
}
if(d!=0){
if(!find_(s1,d)){
ans++;
insert_(s1,d);
}
}
cout<<ans<<endl;
init();
}
return 0;
}
2、POJ2001
题意:给你很多单词,问你每个单词的唯一的最短前缀。
思路:我们先构建好Trie树,然后对每个单词进行find,递归到直到节点出现次数为1,表示这个节点只有这一个单词走过,返
回就ok。
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define ll long long
#define MOD 998244353
#define INF 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int maxn=2e6+5;
int tree[maxn][30]; //tree[i][j]表示节点i的第j个儿子的节点编号
bool flagg[maxn]; //表示以该节点结尾的是一个单词
int sum[maxn]={0};
int tot; //总结点数
void insert_(char *str)
{
int len=strlen(str);
int root=0;
for(int i=0;i<len;i++){
int id=str[i]-'a';
if(!tree[root][id])tree[root][id]=++tot;
sum[tree[root][id]]++;
root=tree[root][id];
}
flagg[root]=true;
}
string find_(char *str)
{
int len=strlen(str);
int root=0;
string ans="";
for(int i=0;i<len;i++)
{
int id=str[i]-'a';
ans+=str[i];
if(sum[tree[root][id]]<=1)return ans;
root=tree[root][id];
}
return ans;
}
void init()
{
for(int i=0;i<=tot;i++)
{
flagg[i]=false;
for(int j=0;j<10;j++)
tree[i][j]=0;
}
tot=0;
}
char s[1005][25];
int main()
{
int num=0;
while(~scanf("%s",s[num])){
insert_(s[num]);
num++;
}
for(int i=0;i<num;i++)
{
printf("%s %s
",s[i],find_(s[i]).c_str());
}
return 0;
}