acwing: https://www.acwing.com/problem/content/837/
在集合中插入字符串,询问字符串在集合中出现了多少次。
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5 + 10;
LL q;
string s;
struct Trie{
LL ch[N][26], cnt[N], idx = 0;
void insert(string s){
LL u = 0;
for (int i = 0; i < s.size(); i ++ ){
LL v = s[i] - 'a';
if (!ch[u][v]) ch[u][v] = ++ idx;
u = ch[u][v];
}
cnt[u] ++ ;
}
LL query(string s){
LL u = 0;
for (int i = 0; i < s.size(); i ++ ){
LL v = s[i] - 'a';
if (!ch[u][v]) return 0;
u = ch[u][v];
}
return cnt[u];
}
}trie;
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> q;
for (int i = 1; i <= q; i ++ ){
char op;
cin >> op >> s;
if (op == 'I'){
trie.insert(s);
}
else{
cout << trie.query(s) << "\n";
}
}
return 0;
}
luogu:https://www.luogu.com.cn/problem/P8306
给定 \(n\) 个模式串 \(s_1, s_2, ..., s_n\) 和 \(q\) 次询问,每次询问给定一个文本串 \(t_i\),问它是多少个模式串的前缀。
#include <bits/stdc++.h>
using namespace std;
#define LL int
const int N = 3e6 + 10;
LL T, n, q;
string s;
struct Trie{
LL ch[N][63], cnt[N], idx = 0;
map <char, LL> mp;
void init(){
LL id = 0;
for (char c = 'a'; c <= 'z'; c ++ )
mp[c] = ++ id;
for (char c = 'A'; c <= 'Z'; c ++ )
mp[c] = ++ id;
for (char c = '0'; c <= '9'; c ++ )
mp[c] = ++ id;
}
void insert(string s){
LL u = 0;
for (int i = 0; i < s.size(); i ++ ){
LL v = mp[s[i]];
if (!ch[u][v]) ch[u][v] = ++ idx;
u = ch[u][v];
cnt[u] ++ ;
}
}
LL query(string s){
LL u = 0;
for (int i = 0; i < s.size(); i ++ ){
LL v = mp[s[i]];
if (!ch[u][v]) return 0;
u = ch[u][v];
}
return cnt[u];
}
void Clear(){
for (int i = 0; i <= idx; i ++ ){
cnt[i] = 0;
for (int j = 0; j <= 62; j ++ ){
ch[i][j] = 0;
}
}
idx = 0;
}
}trie;
void solve(){
cin >> n >> q;
for (int i = 1; i <= n; i ++ ){
cin >> s;
trie.insert(s);
}
for (int i = 1; i <= q; i ++ ){
cin >> s;
cout << trie.query(s) << "\n";
}
trie.Clear();
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
trie.init();
cin >> T;
while (T -- )
solve();
return 0;
}
01 trie
https://www.luogu.com.cn/problem/P4551
给定一棵树,求最大异或路径和。
思路:
先通过 \(dfs\) 求出每个点到根节点的异或和,最大的一段路径和就是在所有点到根节点的路径和中找到异或和最大的那两个。
这题卡空间,需将 ch 改为数组才能过,vector 会超限。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
struct Trie{
int n, idx = 0;
vector<vector<int>> ch;
Trie(int n) : n(n), ch(n * 30, vector<int>(2)) {}
void insert(int x){
int u = 0;
for (int i = 30; ~ i; i -- ){
int &v = ch[u][x >> i & 1];
if (!v) v = ++ idx;
u = v;
}
}
int query(int x){
int u = 0, res = 0;
for (int i = 30; ~ i; i -- ){
int v = x >> i & 1;
if (ch[u][!v]){
res += (1 << i);
u = ch[u][!v];
}
else{
u = ch[u][v];
}
}
return res;
}
};
const int N = 1e5 + 10;
vector<pair<int, int>> e[N];
int a[N];
void dfs(int u, int p){
for (auto [v, w] : e[u]){
if (v == p){
continue;
}
a[v] = a[u] ^ w;
dfs(v, u);
}
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int n;
cin >> n;
for (int i = 1; i < n; i ++ ){
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
dfs(1, 0);
Trie trie(n);
for (int i = 1; i <= n; i ++ ){
trie.insert(a[i]);
}
int ans = 0;
for (int i = 1; i <= n; i ++ ){
ans = max(ans, trie.query(a[i]));
}
cout << ans << "\n";
return 0;
}