const int N = 3000000 + 100; int son[N][62], cnt[N], idx = 0;
插入操作:
两处
void insert(string s){
int p = 0;
for(int i = 0; i < (int)s.size(); i ++){
int u = work(s[i]);
if(!trie[p][u]) trie[p][u] = ++ idx;
p = trie[p][u];
cnt[p] ++;
}
}
查询操作:查询字符串的出现次数
int query(string s){
int p = 0;
for(int i = 0; i < (int)s.size(); i ++){
int u = work(s[i]);
if(!trie[p][u]) return 0;
p = trie[p][u];
}
return cnt[p];
}
额,因为是多组测试,所以得清除上一组保留的数据:
for(int i = 0; i <= idx; i ++){
for(int j = 0; j < 62; j ++) trie[i][j] = 0;
cnt[i] = 0;
}
idx = 0;
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 3000000 + 100;
int trie[N][62], cnt[N], idx = 0;
int work(char x){
if('A' <= x && x <= 'Z') return x - 'A';
else if('a' <= x && x <= 'z') return x - 'a' + 26;
else return x - '0' + 52;
}
void insert(string s){
int p = 0;
for(int i = 0; i < (int)s.size(); i ++){
int u = work(s[i]);
if(!trie[p][u]) trie[p][u] = ++ idx;
p = trie[p][u];
cnt[p] ++;
}
}
int query(string s){
int p = 0;
for(int i = 0; i < (int)s.size(); i ++){
int u = work(s[i]);
if(!trie[p][u]) return 0;
p = trie[p][u];
}
return cnt[p];
}
void solve(){
for(int i = 0; i <= idx; i ++){
for(int j = 0; j < 62; j ++) trie[i][j] = 0;
cnt[i] = 0;
}
idx = 0;
int n, q; cin >> n >> q;
for(int i = 1; i <= n; i ++){
string s; cin >> s;
insert(s);
}
while(q --){
string s; cin >> s;
cout << query(s) << endl;
}
return ;
}
signed main(){
HelloWorld;
int tt = 1;
cin >> tt;
while(tt --) solve();
return 0;
}
一点点逆向思维
总代码:
题目三:https://www.luogu.com.cn/problem/P10471
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 1000000 + 100;
int trie[N][26], cnt[N], idx = 0;
void insert(string s){
int p = 0;
for(int i = 0; i < (int)s.size(); i ++){
int u = s[i] - 'a';
if(!trie[p][u]) trie[p][u] = ++ idx;
p = trie[p][u];
}
cnt[p] ++;
}
int query(string s){
int ans = 0, p = 0;
for(int i = 0; i < (int)s.size(); i ++){
int u = s[i] - 'a';
if(!trie[p][u]) return ans;
p = trie[p][u];
ans += cnt[p];
}
return ans;
}
void solve(){
int n, m; cin >> n >> m;
for(int i = 1; i <= n; i ++){
string s; cin >> s;
insert(s);
}
for(int i = 1; i <= m; i ++){
string s; cin >> s;
cout << query(s) << endl;
}
return ;
}
signed main(){
HelloWorld;
int tt = 1;
while(tt --) solve();
return 0;
}
题目三:https://www.luogu.com.cn/problem/P10471
很经典的一道题目,如果不知道用字典树的话,就会陷入
暴力循环枚举中
把每一个整数看作长度为
的二进制
串,然后将
串插入到字典树中。遍历
到
,枚举每一个
,然后在二进制上找对应进制相反的进制,如果相反的进制对应的值为空,那么只好相同为
了
注意从大到小开始插入,这样可以求得最大值
最多会有
个节点,所以
取值为
总代码:
题目四:https://www.luogu.com.cn/problem/P4551
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 5000000 + 100;
int trie[N][2], idx = 0;
void insert(int x){
int p = 0;
for(int i = 32; i >= 0; i --){
int u = (x >> i) & 1;
if(!trie[p][u]) trie[p][u] = ++ idx;
p = trie[p][u];
}
}
int query(int x){
int ans = 0, p = 0;
for(int i = 32; i >= 0; i --){
int u = (x >> i) & 1;
if(trie[p][!u]){
ans += (1LL << i);
p = trie[p][!u];
}
else p = trie[p][u];
}
return ans;
}
void solve(){
int n; cin >> n;
vector<int> a(n + 10);
for(int i = 1; i <= n; i ++){
cin >> a[i];
insert(a[i]);
}
int ans = 0;
for(int i = 1; i <= n; i ++) ans = max(ans, query(a[i]));
cout << ans << endl;
return ;
}
signed main(){
HelloWorld;
int tt = 1;
while(tt --) solve();
return 0;
}
题目四:https://www.luogu.com.cn/problem/P4551
设
表示节点
与根节点的异或路径值,那么求树中所有异或路径的最大值,就是求两个节点
,满足
值最大
-
就是
的异或路径值,额,很显然了,与
一样的道理
那么可以用
搜索预处理出所有节点的
值,然后找两个节点
,满足
值最大,就是题目三
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 100000 + 100;
int n, d[N];
vector<pair<int, int> > adj[N];
int trie[N * 33][2], idx;
void dfs(int u, int fa, int sum){
d[u] = sum;
for(auto [v, w] : adj[u]){
if(v == fa) continue;
dfs(v, u, sum ^ w);
}
}
void insert(int x){
int p = 0;
for(int i = 32; i >= 0; i --){
int u = (x >> i) & 1;
if(!trie[p][u]) trie[p][u] = ++ idx;
p = trie[p][u];
}
}
int query(int x){
int ans = 0, p = 0;
for(int i = 32; i >= 0; i --){
int u = (x >> i) & 1;
if(trie[p][!u]){
ans += (1LL << i);
p = trie[p][!u];
}
else p = trie[p][u];
}
return ans;
}
void solve(){
cin >> n;
for(int i = 1; i <= n - 1; i ++){
int u, v, w; cin >> u >> v >> w;
adj[u].push_back({v, w});
adj[v].push_back({u, w});
}
dfs(1, -1, 0);
for(int i = 1; i <= n; i ++) insert(d[i]);
int ans = 0;
for(int i = 1; i <= n; i ++) ans = max(ans, query(d[i]));
cout << ans << endl;
return ;
}
signed main(){
HelloWorld;
int tt = 1;
while(tt --) solve();
return 0;
}
题目五:https://codeforces.com/problemset/problem/1285/D
首先将
个数的二进制
串存入
中,然后想如何求最小值,
,第一位表示权值,第二位表示枚举的二进制位置
-
如果第
位全是
,即
,那么返回
-
如果第
位全是
,即
,那么返回
-
如果第
位既有
也有
,那就返回
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 100000 + 100;
int trie[32 * N][2], idx = 0;
int n, a[N], ans;
void insert(int x){
int p = 0;
for(int i = 32; i >= 0; i --){
int u = (x >> i) & 1;
if(!trie[p][u]) trie[p][u] = ++ idx;
p = trie[p][u];
}
}
int dfs(int p, int x){
if(x < 0) return 0;
if(!trie[p][0]) return dfs(trie[p][1], x - 1);
if(!trie[p][1]) return dfs(trie[p][0], x - 1);
return min(dfs(trie[p][0], x - 1), dfs(trie[p][1], x - 1)) + (1LL << x);
}
void solve(){
cin >> n;
for(int i = 1; i <= n; i ++){
cin >> a[i];
insert(a[i]);
}
cout << dfs(0, 32);
return ;
}
signed main(){
HelloWorld;
int tt = 1;
while(tt --) solve();
return 0;
}



京公网安备 11010502036488号