Trie专题练习记录 1
HDU 1251 统计难题
Solution:
\(Trie\)。插入字符串时,将前缀链上的所有结点的点权加一,代表该前缀出现次数。查询时直接返回出现次数即可。注意输入格式。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=11;
const int M=5e5+10;
char s[N];
int tr[M][26];
int endpos[M];
struct trie
{
int tot;//点数
int rt;//根
void init(){
tot=0;
rt=0;
}
void insert1(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]++;
}
}
int 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 0;
pos=tr[pos][v];
}
return endpos[pos];
}
};
int main(){
trie T;
T.init();
while(cin.getline(s,N)){
int len=strlen(s);
if(len==0)break;
T.insert1(s,len);
}
while(cin.getline(s,N)){
int len=strlen(s);
printf("%d\n", T.query(s,len));
}
return 0;
}
\(\rule[0pt]{38.3cm}{0.05cm}\)
HDU 4825 Xor Sum
Solution:
\(Trie\)经典题。将所有数二进制拆分后插入字典树中,每次询问\(x\),对于\(x\)二进制数的每一位,尽量往相反方向走,最后统计答案即可。
Code:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
using namespace std;
const int N=3e6+10;
int tr[N][2];
typedef long long ll;
struct trie{
int tot;
int rt;
void insert(ll val){
int pos=rt;
for(ll i=33;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=33;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;
}
};
int n,m;
ll q[100005];
int main(){
int cas=0;
int t;
trie T;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=0;i<=T.tot;++i){
for(int j=0;j<=1;++j)
tr[i][j]=0;
}
T.init();
for(int i=1;i<=n;++i){
scanf("%lld",&q[i]);
T.insert(q[i]);
}
printf("Case #%d:\n",++cas);
for(int i=1;i<=m;++i){
ll x;
scanf("%lld",&x);
printf("%lld\n",T.query(x));
}
}
return 0;
}
\(\rule[0pt]{38.3cm}{0.05cm}\)
HDU 5536 Chip Factory
Solution:
\(Trie\)。先将所有数拆分成二进制插入到\(Trie\)中,统计每一位出现的次数。\(n^2\)暴力枚举\(s_i+s_j\),对于每一组\(s_i+s_j\),先在\(Trie\)中将\(s_i\)和\(s_j\)分别删去,即将\(s_i\)和\(s_j\)的每一位二进制对应的出现次数减一,再做一遍经典的异或最大值查询,然后要记得把\(s_i\)和\(s_j\)加回去,还原\(Trie\),最后对所有结果求\(max\)即可。
Code:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
using namespace std;
const int N=3e6+10;
int tr[N][2];
typedef long long ll;
int cnt[N];
struct trie{
int tot;
int rt;
void insert(ll val){
int pos=rt;
for(ll i=33;i>=0;--i){
int v = (1&(val>>(i*1ll)));
if(!tr[pos][v])tr[pos][v]=++tot;
pos = tr[pos][v];
cnt[pos]++;
}
}
ll query(ll val,ll x,ll y){
int pos=rt;
ll ans=0;
for(ll i=33;i>=0;--i){
int v = (1&(x>>(i*1ll)));
pos=tr[pos][v];
cnt[pos]--;
}
pos=rt;
for(ll i=33;i>=0;--i){
int v = (1&(y>>(i*1ll)));
pos=tr[pos][v];
cnt[pos]--;
}
pos=rt;
for(ll i=33;i>=0;--i){
int v = (1&(val>>(i*1ll)));
if(cnt[tr[pos][v]]==0&&cnt[tr[pos][v^1]]==0)break;
else if(cnt[tr[pos][v]]!=0&&cnt[tr[pos][v^1]]==0){
pos=tr[pos][v];
ans=ans+(1ll*(1<<i))*(v);
}
else if(cnt[tr[pos][v]]==0&&cnt[tr[pos][v^1]]!=0){
pos=tr[pos][v^1];
ans=ans+(1ll*(1<<i))*(v^1);
}
else{
pos=tr[pos][v^1];
ans=ans+(1ll*(1<<i))*(v^1);
}
}
pos=rt;
for(ll i=33;i>=0;--i){
int v = (1&(x>>(i*1ll)));
pos=tr[pos][v];
cnt[pos]++;
}
pos=rt;
for(ll i=33;i>=0;--i){
int v = (1&(y>>(i*1ll)));
pos=tr[pos][v];
cnt[pos]++;
}
return ans;
}
void init(){
tot=rt=0;
}
};
int n,m;
ll q[100005];
int main(){
int cas=0;
int t;
trie T;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<=T.tot;++i){
for(int j=0;j<=1;++j)
tr[i][j]=0;
cnt[i]=0;
}
T.init();
for(int i=1;i<=n;++i){
scanf("%lld",&q[i]);
T.insert(q[i]);
}
ll mx=0;
for(int i=1;i<=n;++i){
for(int j=i+1;j<=n;++j){
if(i==j)continue;
ll val=q[i]+q[j];
mx=max(mx,T.query(val,q[i],q[j])^val);
}
}
printf("%lld\n",mx);
}
return 0;
}
\(\rule[0pt]{38.3cm}{0.05cm}\)
POJ 2001 Shortest Prefixes
Solution:
\(Trie\)。将所有字符串插入,维护\(cnt\)记录每个前缀出现的次数。依次对每个串进行查询,第一次遇到出现次数为\(1\)的前缀即为该字符串的答案。
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 cnt[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];
cnt[pos]++;
}
endpos[pos] = 1;
}
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];
if(cnt[pos]==1)return i+1;
}
return lens;
}
void init(){
tot=rt=0;
}
};
char sp[1001][21];
int main(){
trie T;
T.init();
int con=0;
while(scanf("%s",sp[++con])!=EOF){
T.insert(sp[con],strlen(sp[con]));
}
for(int i=1;i<=con;++i){
int vlen=T.query(sp[i],strlen(sp[i]));
printf("%s ",sp[i]);
for(int j=0;j<vlen;++j)printf("%c",sp[i][j]);
puts("");
}
}