字典树中根到每个结点对应原串集合的一个前缀,这个前缀由路径上所有转移边对应的字母构成。我们可以对每个结点维护一些需要的信息,这样即可以去做很多事情。

#10049. 「一本通 2.3 例 1」Phone List

#include <bits/stdc++.h>
using namespace std; namespace Trie {
struct Node {
Node *ch[];
int val;
Node* clear() {
for(int i=;i<;i++) ch[i]=NULL;
val=;
return this;
}
}; Node *root;
Node pool[];
int ind=;
Node* newnode() {
return pool[ind++].clear();
} void clear() {
ind=;
root=newnode();
}
void insert(string s) {
Node *pos=root;
for(int i=;i<s.length();i++) {
if(pos->ch[s[i]]==NULL) pos->ch[s[i]]=newnode();
pos->val++;
pos=pos->ch[s[i]];
}
}
int query(string s) {
Node *pos=root;
for(int i=;i<s.length();i++) {
if(pos->ch[s[i]]==NULL) return ;
pos=pos->ch[s[i]];
}
return pos->val;
} string str[]; void solve() {
int n;
cin>>n;
clear();
for(int i=;i<=n;i++) {
cin>>str[i];
for(int j=;j<str[i].length();j++) str[i][j] -= '';
insert(str[i]);
}
int flag=;
for(int i=;i<=n;i++) {
if(query(str[i])) {
flag=;
break;
}
}
if(flag) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
} int main() {
int t;
ios::sync_with_stdio(false);
cin>>t;
while(t--) Trie::solve();
return ;
}

#10050. 「一本通 2.3 例 2」The XOR Largest Pair

0-1 Trie通常用于异或相关的问题,思路是记录所有01串后,我们找最大异或和的时候可以从高位到低位贪心,此时Trie发挥的作用就是在当前前缀已经选择的情况下,能使得正在考虑位异或为1的后缀是否存在。

#include <bits/stdc++.h>
using namespace std; namespace Trie {
struct Node {
Node *ch[];
Node *clear() {
ch[] = ch[] = ;
return this; // Don't forget this
}
};
Node *root;
Node pool[];
int ind;
Node *newnode() { return pool[ind++].clear(); }
void insert(int x) {
Node *pos = root;
for (int i = ; i >= ; --i) {
int b = (x / ( << i)) & ;
if (pos->ch[b] == NULL)
pos->ch[b] = newnode();
pos = pos->ch[b];
}
}
int query(int x) {
Node *pos = root;
int ans = ;
for (int i = ; i >= && pos != NULL; --i) {
int b = (x / ( << i)) & ;
if (pos->ch[b ^ ] != NULL)
pos = pos->ch[b ^ ], ans += ( << i);
else
pos = pos->ch[b];
}
return ans;
}
int a[];
void solve() {
int n, ans = ;
cin >> n;
root = newnode(); // Don't forget this
for (int i = ; i <= n; i++) cin >> a[i], insert(a[i]);
for (int i = ; i <= n; i++) ans = max(ans, query(a[i]));
cout << ans << endl;
}
} // namespace Trie int main() {
ios::sync_with_stdio(false);
Trie::solve();
}

#10051. 「一本通 2.3 例 3」Nikitosh 和异或

看到这个算式我们很容易想到前缀和转化。问题转化为求s[r1]^s[l1-1] + s[r2]^s[l2-1]最大。

由于要r1<l2,所以可考虑去处理出一个前缀max和一个后缀max,然后枚举分界点。那么答案就是

Max{pre[i]+suf[i+1]}

#include <bits/stdc++.h>
using namespace std; namespace Trie {
struct Node {
Node *ch[];
Node *clear() {
ch[] = ch[] = ;
return this; // Don't forget this
}
};
Node *root;
Node pool[];
int ind;
Node *newnode() { return pool[ind++].clear(); }
void insert(int x) {
Node *pos = root;
for (int i = ; i >= ; --i) {
int b = (x / ( << i)) & ;
if (pos->ch[b] == NULL)
pos->ch[b] = newnode();
pos = pos->ch[b];
}
}
int query(int x) {
Node *pos = root;
int ans = ;
for (int i = ; i >= && pos != NULL; --i) {
int b = (x / ( << i)) & ;
if (pos->ch[b ^ ] != NULL)
pos = pos->ch[b ^ ], ans += ( << i);
else
pos = pos->ch[b];
}
return ans;
}
int a[], pre[], suf[];
void solve() {
int n, ans = ;
cin >> n;
root = newnode(); // Don't forget this
for (int i = ; i <= n; i++) cin >> a[i], insert(a[i]), pre[i] = max(pre[i - ], query(a[i]));
ind = ;
root = newnode();
reverse(a + , a + n + );
for (int i = ; i <= n; i++) insert(a[i]), suf[i] = max(suf[i - ], query(a[i]));
reverse(suf + , suf + n + );
for (int i = ; i < n; i++) ans = max(ans, pre[i] + suf[i + ]);
cout << ans << endl;
}
} // namespace Trie int main() {
ios::sync_with_stdio(false);
Trie::solve();
}

#10052. 「一本通 2.3 练习 1」Immediate Decodability

和前面那题一样

#include <bits/stdc++.h>
using namespace std; namespace Trie {
struct Node {
Node *ch[];
int val;
Node *clear() {
for (int i = ; i < ; i++) ch[i] = NULL;
val = ;
return this;
}
}; Node *root;
Node pool[];
int ind = ;
Node *newnode() { return pool[ind++].clear(); } void clear() {
ind = ;
root = newnode();
}
void insert(string s) {
Node *pos = root;
for (int i = ; i < s.length(); i++) {
if (pos->ch[s[i]] == NULL)
pos->ch[s[i]] = newnode();
pos->val++;
pos = pos->ch[s[i]];
}
}
int query(string s) {
Node *pos = root;
for (int i = ; i < s.length(); i++) {
if (pos->ch[s[i]] == NULL)
return ;
pos = pos->ch[s[i]];
}
return pos->val;
} string str[]; bool solve(int t) {
clear();
int n = ;
while (cin >> str[++n]) {
if (str[n][] == '')
break;
for (int j = ; j < str[n].length(); j++) str[n][j] -= '';
insert(str[n]);
}
--n;
if (n <= )
return false;
int flag = ;
for (int i = ; i <= n; i++) {
if (query(str[i])) {
flag = ;
break;
}
}
if (flag)
cout << "Set " << t << " is not immediately decodable" << endl;
else
cout << "Set " << t << " is immediately decodable" << endl;
return true;
}
} // namespace Trie int main() {
int t = ;
ios::sync_with_stdio(false);
while (Trie::solve(++t))
;
return ;
}

#10053. 「一本通 2.3 练习 2」L 语言

我们记录u[i]表示文章的每一个前缀s[1..i]是否可被理解。做一个类似dp的处理即可。

刚开始忘记传引用T了半天……

#include <bits/stdc++.h>
using namespace std; char buf[]; void readstr(string &tar) {
scanf("%s", buf);
tar = buf;
} int __cnt = ; namespace Trie {
struct Node {
Node *ch[];
int val;
Node *clear() {
for (int i = ; i < ; i++) ch[i] = NULL;
val = ;
return this;
}
}; Node *root;
Node pool[];
int u[];
int ind = , ans = ;
Node *newnode() { return pool[ind++].clear(); } void clear() {
ind = ;
root = newnode();
}
void insert(string &s) {
Node *pos = root;
for (int i = ; i < s.length(); i++) {
if (pos->ch[s[i]] == NULL)
pos->ch[s[i]] = newnode();
pos = pos->ch[s[i]];
}
pos->val++;
}
void query(string &s, int start) {
Node *pos = root;
int len = s.length();
for (int i = start; i < len; i++) {
__cnt++;
if (pos->ch[s[i]] == NULL)
return;
pos = pos->ch[s[i]];
if (pos->val)
u[i + ] = , ans = max(ans, i + );
}
} string str[];
string art; void solve() {
int n, m;
scanf("%d%d", &n, &m);
clear();
for (int i = ; i <= n; i++) {
readstr(str[i]);
for (int j = ; j < str[i].length(); j++) str[i][j] -= 'a';
insert(str[i]);
}
for (int i = ; i <= m; i++) {
ans = ;
memset(u, , sizeof u);
readstr(art);
int len = art.length();
for (int j = ; j < len; j++) art[j] -= 'a';
u[] = ;
for (int j = ; j < len; j++) {
if (u[j] == )
continue;
query(art, j);
}
cout << ans << endl;
}
}
} // namespace Trie int main() {
int t;
ios::sync_with_stdio(false);
Trie::solve();
// cout<<__cnt<<endl;
return ;
}

#10054. 「一本通 2.3 练习 3」Secret Message 秘密信息

对信息建Trie,仍然是在每个串的结束点上打标记。结果就等于把密码串丢上去跑,跑的路径上的标记和,加上最终停在的结点(如果整个密码串都成功匹配)的子树的标记和。前一个直接记录,后一个用树上前缀和预处理一下即可。

#include <bits/stdc++.h>
using namespace std; namespace Trie {
struct Node {
Node *ch[];
int val, sum;
Node *clear() {
for (int i = ; i < ; i++) ch[i] = NULL;
val = sum = ;
return this;
}
}; Node *root;
Node pool[];
int ind = ;
Node *newnode() { return pool[ind++].clear(); } void clear() {
ind = ;
root = newnode();
}
void insert(int len) {
Node *pos = root;
for (int i = ; i < len; i++) {
int si;
cin >> si;
if (pos->ch[si] == NULL)
pos->ch[si] = newnode();
pos = pos->ch[si];
}
pos->val++;
}
void dfs(Node *p) {
if (p == NULL)
return;
dfs(p->ch[]);
dfs(p->ch[]);
p->sum = p->val;
if (p->ch[])
p->sum += p->ch[]->sum;
if (p->ch[])
p->sum += p->ch[]->sum;
}
int query(int len) {
Node *pos = root;
int ans = ;
for (int i = ; i < len; i++) {
int si;
cin >> si;
ans += pos->val;
if (pos->ch[si] == NULL) {
for (int j = ; j <= len - i - ; j++) cin >> si;
return ans;
}
pos = pos->ch[si];
}
return ans + pos->sum;
} string str[]; void solve() {
int m, n;
cin >> m >> n;
clear();
for (int i = ; i <= m; i++) {
int len;
cin >> len;
insert(len);
}
dfs(root);
for (int i = ; i <= n; i++) {
int len;
cin >> len;
cout << query(len) << endl;
}
}
} // namespace Trie int main() {
int t;
ios::sync_with_stdio(false);
Trie::solve();
return ;
}

#10056. 「一本通 2.3 练习 5」The XOR-longest Path

树上前缀异或和以后直接转化为两点最大异或和。其实用欧拉序也可以。

#include <bits/stdc++.h>
using namespace std; namespace Trie {
struct Node {
Node *ch[];
Node* clear() {
ch[]=ch[]=;
return this; // Don't forget this
}
};
Node *root;
Node pool[];
int ind;
Node* newnode() {
return pool[ind++].clear();
}
void insert(int x) {
Node *pos = root;
for(int i=;i>=;--i) {
int b=(x/(<<i))&;
if(pos->ch[b]==NULL) pos->ch[b]=newnode();
pos=pos->ch[b];
}
}
int query(int x) {
Node *pos = root;
int ans = ;
for(int i=;i>= && pos!=NULL;--i) {
int b=(x/(<<i))&;
if(pos->ch[b^]!=NULL)
pos=pos->ch[b^], ans+=(<<i);
else pos=pos->ch[b];
}
return ans;
}
int a[];
void solve(int n) {
int ans=;
root=newnode(); // Don't forget this
for(int i=;i<=n;i++) insert(a[i]);
for(int i=;i<=n;i++) ans=max(ans,query(a[i]));
cout<<ans<<endl;
}
}
int n,vis[];
vector<pair<int,int> > g[]; void dfs(int p) {
vis[p]=;
for(int i=;i<g[p].size();i++) {
int q=g[p][i].first;
if(vis[q]==) {
Trie::a[q]=Trie::a[p] ^ g[p][i].second;
dfs(q);
}
}
} int main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=;i<n;i++) {
int u,v,w;
cin>>u>>v>>w;
g[u].push_back(make_pair(v,w));
g[v].push_back(make_pair(u,w));
}
dfs();
Trie::solve(n);
}

[一本通学习笔记] 字典树与 0-1 Trie的更多相关文章

  1. 《python基础教程(第二版)》学习笔记 字典(第4章)

    <python基础教程(第二版)>学习笔记 字典(第4章)创建字典:d={'key1':'value1','key2':'value2'}lst=[('key1','value1'),(' ...

  2. 一起学ASP.NET Core 2.0学习笔记(二): ef core2.0 及mysql provider 、Fluent API相关配置及迁移

    不得不说微软的技术迭代还是很快的,上了微软的船就得跟着她走下去,前文一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx.superviso ...

  3. 算法笔记--字典树(trie 树)&& ac自动机 && 可持久化trie

    字典树 简介:字典树,又称单词查找树,Trie树,是一种树形结构,是哈希树的变种. 优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较. 性质:根节点不包含字符,除根节点外每一个 ...

  4. [一本通学习笔记] AC自动机

    AC自动机可以看作是在Trie树上建立了fail指针,在这里可以看作fail链.如果u的fail链指向v,那么v的对应串一定是u对应串在所给定字符串集合的后缀集合中的最长的后缀. 我们考虑一下如何实现 ...

  5. 学习笔记-动态树Link-Cut-Tree

    --少年你有梦想吗? --少年你听说过安利吗? 安利一个集训队讲解:http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 关于动态树问题,有多种方法 ...

  6. NVIDIA DIGITS 学习笔记(NVIDIA DIGITS-2.0 + Ubuntu 14.04 + CUDA 7.0 + cuDNN 7.0 + Caffe 0.13.0)

    转自:http://blog.csdn.net/enjoyyl/article/details/47397505?from=timeline&isappinstalled=0#10006-we ...

  7. Python学习笔记(字典)

    今天学习一个python中的基本类型--字典(dictionary) 字典这种数据结构有点像我们平常用的通讯录,有一个名字和这个名字对应的信息.在字典中,名字叫做“键”,对应的内容信息叫做“值”.字典 ...

  8. [一本通学习笔记] 最近公共祖先LCA

    本节内容过于暴力没什么好说的.借着这个专题改掉写倍增的陋习,虽然写链剖代码长了点不过常数小还是很香. 10130. 「一本通 4.4 例 1」点的距离 #include <bits/stdc++ ...

  9. [一本通学习笔记] RMQ专题

    傻傻地敲了好多遍ST表. 10119. 「一本通 4.2 例 1」数列区间最大值 #include <bits/stdc++.h> using namespace std; const i ...

随机推荐

  1. 制作MySQL RPM安装包Spec

    适用环境: 数据库版本:MySQL 操作系统:CentOS 7 制作思路: 将数据库初始化和配置工作放到安装脚本中方便定制: 1.打包MySQL应用目录 2.不自动生成配置文件 3.不自动生成数据目录 ...

  2. opencv —— createTrackbar、getTrackbarPos 滑动条的创建和使用

    创建滑动条:createTrackbar 函数 createTrackbar 函数用于创建一个可以调整数值的滑动条,并将滑动条附加在指定的窗口上. int createTrackbar(const s ...

  3. 剑指offer-面试题29-顺时针打印矩阵-矩阵

    /* 题目: 输入一个矩阵,按照从外到内顺时针的顺序依次打印每一个数字. */ /* 思路: 1.将打印矩阵看作是打印一个个从外向内的环. 2.每一个环都有一个起始节点,起始节点的坐标*2小于行数和列 ...

  4. 2020 CCPC Wannafly Winter Camp Day1 Div.1&amp F

    #include<bits/stdc++.h> #define forn(i, n) for (int i = 0; i < int(n); i++) #define fore(i, ...

  5. C# 一次循环获取树的两种方法

    第一种方法好些 第二种方法如果中间断开就会成为一级 private static List<Menu> MenuTree() { , ParentId = , Name = "a ...

  6. Sentence by defender

    也许,人在旅途,不是你看清了多少事,而是你看轻了多少事.

  7. Python之六:模块

    模块包含了大量的函数方法和变量,我们可以用下面的语句调用模块: import 模块名 这样我们就可以在后面的语句中使用模块中的函数或者变量了.调用时只需用    模块名.函数名的方式调用即可 from ...

  8. Spring学习笔记-装配Bean-02

    什么是装配 创建应用对象之间写作关系的行为通常称为装配(wiring),这也是依赖注入(DI)的本质. Spring配置的可选方案 Spring提供了3中主要的装配机制: ● 在XML中进行显式配置. ...

  9. Spark学习之路 (一)Spark初识 [转]

    官网介绍 什么是Spark 官网地址:http://spark.apache.org/ Apache Spark™是用于大规模数据处理的统一分析引擎. 从右侧最后一条新闻看,Spark也用于AI人工智 ...

  10. 扩展BSGS求解离散对数问题

    扩展BSGS用于求解axΞb mod(n) 同余方程中gcd(a,n)≠1的情况 基本思路,将原方程转化为a与n互质的情况后再套用普通的BSGS求解即可 const int maxint=((1< ...