Trie专题练习记录 2
HDU 2072 单词数
Solution:
\(Trie\)。解题方法不唯一,此处方法如下。
每一次插入前,判断该字符串是否出现在\(Trie\)中,若出现则满足查询时结尾存在\(endpos[pos]!=0\),跳过。
若没出现过,则\(ans\)加一,将该字符串插入\(Trie\)中,结尾处打上标记\(endpos[pos]=1\)。最后输出\(ans\)即可,注意输入格式和多样例清空。
Code:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
#include<unordered_map>
using namespace std;
const int N=5e5+10;
int tr[N][26];
bool endpos[N];
struct trie{
int tot;
int rt;
void insert(char s[],int lens){
int pos=rt;
for(int i=0;i<lens;++i){
int v = s[i] - 'a';
if(!tr[pos][v])tr[pos][v]=++tot;
pos = tr[pos][v];
}
endpos[pos] = 1;
}
bool query(char s[],int lens){
int pos=rt;
for(int i=0;i<lens;++i){
int v = s[i] - 'a';
if(!tr[pos][v])return false;
pos=tr[pos][v];
}
return (endpos[pos]!=0);
}
void init(){
tot=rt=0;
}
};
char s[N];
char newc[N];
int nlen;
int main(){
trie T;
T.init();
int ans=0;
int c=0;
while(cin.getline(s,N-1)){
nlen=0;
ans=0;
for(int i=0;i<=T.tot;++i){
for(int j=0;j<=25;++j)
tr[i][j]=0;
endpos[i]=0;
}
T.init();
int lens=strlen(s);
if(s[0]=='#')break;
for(int i=0;i<lens;++i){
if(s[i]==' ')continue;
int pos=i;
nlen=0;
while(s[pos]>='a'&&s[pos]<='z'){
newc[nlen++]=s[pos];
pos++;
}
i=pos;
if(T.query(newc,nlen)){
continue;
}
else {
ans++;
T.insert(newc,nlen);
}
}
printf("%d\n",ans);
}
}
HDU 1305 Immediate Decodability
Solution:
\(Trie\)。判断是否有一个串是其他串的前缀。统计所有前缀出现次数,记录下每个串的\(endpos\)位置,如果这些位置存在出现次数大于一,则存在一个串是另一个串的前缀。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
const int M=2e5+10;
int tr[M][10];
int endpos[M];
int cnt[M];
int q[M];
struct trie
{
int tot;//点数
int rt;//根
void init(){
tot=0;
rt=0;
}
void insert(char s[],int lens,int id){
int pos=rt;
for(int i=0;i<lens;++i){
int v=s[i]-'0';
if(!tr[pos][v])tr[pos][v]=++tot;
pos=tr[pos][v];
cnt[pos]++;
}
q[id] = pos;
}
};
char s[N];
int main(){
trie T;
T.init();
int con=0;
int ca=0;
while(scanf("%s",s)!=EOF){
if(s[0]=='9'){
int flag=1;
for(int i=1;i<=con;++i){
if(cnt[q[i]]>1){
flag=0;
break;
}
}
if(flag)printf("Set %d is immediately decodable\n",++ca);
else printf("Set %d is not immediately decodable\n",++ca);
con=0;
for(int i=0;i<=T.tot;++i){
for(int j=0;j<=9;++j){
tr[i][j]=0;
}
cnt[i]=0;
}
continue;
}
T.insert(s,strlen(s),++con);
}
return 0;
}
POJ 3764 The xor-longest Path
Solution:
\(Trie\),树上异或最大值经典题。记录根节点到节点\(i\)的异或和\(q[i]\),那么\(x\),\(y\)两点路径的异或和为\((q[x])xor(q[y])\)。
问题转换成给定若干权值,选两个使异或和最大。
考虑依次往\(Trie\)中插入\(q[i]\),每次在插入前查询字典树中与\(q[i]\)的异或最大值为\(val_i\),最后答案显然为\(max(val_i)\)。
如何求\(val_i\),异或最大值经典题中有讲解到。
Code:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
using namespace std;
const int N=1e5+10;
int tr[N*10][2];
typedef long long ll;
struct trie{
int tot;
int rt;
void insert(ll val){
int pos=rt;
for(ll i=32;i>=0;--i){
int v = (1&(val>>(i*1ll)));
if(!tr[pos][v])tr[pos][v]=++tot;
pos = tr[pos][v];
}
}
ll query(ll val){
int pos=rt;
ll ans=0;
for(ll i=32;i>=0;--i){
int v = (1&(val>>(i*1ll)));
if(!tr[pos][v^1]){
pos=tr[pos][v];
ans=ans+(1ll*(1<<i))*(v);
}
else if(tr[pos][v^1]){
pos=tr[pos][v^1];
ans=ans+(1ll*(1<<i))*(v^1);
}
}
return ans;
}
void init(){
tot=rt=0;
}
};
const int M=N*2;
int ne[M],e[M];
int w[M];
int head[N];
int idx=0;
int n;
void add(int u,int v,int z){
ne[++idx]=head[u],e[idx]=v,w[idx]=z,head[u]=idx;
}
ll q[N];
void dfs(int u,int fa,ll xsum){
q[u] = xsum;
for(int i=head[u];i;i=ne[i]){
int to = e[i];
ll z = w[i];
if(to == fa)continue;
dfs(to,u,xsum^z);
}
}
int main(){
trie T;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<=T.tot;++i){
for(int j=0;j<=1;++j){
tr[i][j]=0;
}
}
for(int i=0;i<n;++i)head[i]=0;
idx=0;
T.init();
for(int i=1;i<=n-1;++i){
int u,v,z;
scanf("%d %d %d",&u,&v,&z);
add(u,v,z);
add(v,u,z);
}
dfs(0,-1,0);
ll mx=0;
for(int i=0;i<n;++i){
mx=max(mx,T.query(q[i])^q[i]);
T.insert(q[i]);
}
printf("%lld\n",mx);
}
return 0;
}
POJ 2503 Babelfish
Solution:
\(Trie\)。根据题意模拟即可,方法不唯一。
Code:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
using namespace std;
const int N=5e5+10;
int tr[N][26];
bool endpos[N];
int idpos[N];
int cnt[N];
struct trie{
int tot;
int rt;
void insert(char s[],int lens,int id){
int pos=rt;
for(int i=0;i<lens;++i){
int v = s[i] - 'a';
if(!tr[pos][v])tr[pos][v]=++tot;
pos = tr[pos][v];
idpos[pos]=id;
}
}
int query(char s[],int lens){
int pos=rt;
int ans=0;
for(int i=0;i<lens;++i){
int v = s[i] - 'a';
if(!tr[pos][v])return false;
pos=tr[pos][v];
}
return idpos[pos];
}
void init(){
tot=rt=0;
}
};
char s1[100001][11];
char s2[100001][11];
char s[23];
int main(){
trie T;
T.init();
int con=0;
while(cin.getline(s,22)){
int len=strlen(s);
if(len==0)break;
int pos=0;
++con;
for(int i=0;i<len;++i){
if(s[i]==' '){
pos=i;break;
}
s1[con][i]=s[i];
}
int cc=0;
for(int i=pos+1;i<len;++i){
s2[con][cc++]=s[i];
}
T.insert(s2[con],cc,con);
}
while(scanf("%s",s)!=EOF){
int len=strlen(s);
int va=T.query(s,len);
if(va==0)puts("eh");
else printf("%s\n",s1[va]);
}
}
HDU 1247 Hat’s Words
Solution:
\(Trie\)。每个单词的最大长度不超过\(50\)。
先将所有字符串长度从小到大排序,保证字符串\(i\)的可能前缀在\([1,i-1]\)中已经插入。
查询时枚举前缀,遇到\(endpos=1\)的位置时,截取字符串,返回根节点重新查询剩余部分,若最后剩余部分结尾存在\(endpos=1\),则该字符串符合答案要求。
将所有答案按字典序排序,注意输出即可。
Code:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
#include<unordered_map>
using namespace std;
const int N=2e5+10;
int tr[N][26];
bool endpos[N];
struct trie{
int tot;
int rt;
void insert(char s[],int lens,int id){
int pos=rt;
for(int i=0;i<lens;++i){
int v = s[i] - 'a';
if(!tr[pos][v])tr[pos][v]=++tot;
pos = tr[pos][v];
}
endpos[pos] = 1;
}
bool query(char s[],int lens){
int pos=rt;
for(int i=0;i<lens;++i){
int v = s[i] - 'a';
if(!tr[pos][v])return false;
pos=tr[pos][v];
if(endpos[pos]){
if(query1(s,i+1,lens))return true;
}
}
return false;
}
bool query1(char s[],int st,int lens){
int pos=rt;
for(int i=st;i<lens;++i){
int v=s[i] - 'a';
if(!tr[pos][v])return false;
pos=tr[pos][v];
}
if(endpos[pos]){
return true;
}
else return false;
}
void init(){
tot=rt=0;
}
};
bool cmp(string a,string b){
return (int)a.length()<(int)b.length();
}
bool cmp1(string a,string b){
return a<b;
}
string ans[N];
char newc[N];
int ansid[N];
string s[N];
int main(){
trie T;
T.init();
string ss;
int con=0;
while(cin>>ss){
s[++con]=ss;
}
sort(s+1,s+1+con,cmp);
int cans=0;
for(int i=1;i<=con;++i){
int cnt=0;
int len=s[i].size();
for(int j=0;j<len;++j){
newc[cnt++]=s[i][j];
}
if(T.query(newc,len)){
ans[++cans]=s[i];
}
T.insert(newc,cnt,i);
}
sort(ans+1,ans+1+cans,cmp1);
for(int i=1;i<=cans;++i){
cout<<ans[i]<<"\n";
}
return 0;
}