字典树小记
普通字典树
没什么好讲的
0-1 Trie
非常有用,经常用于异或相关的题目
求一个集合中两两异或的最大值
枚举集合中的一个数 \(x\),按位贪心,如果这一位有一个与 \(x\) 不同的,那么字典树上走这一边,否则走 \(x\) 的这一边。具体见代码
int solve(int x){
int p = 1, o = 0, ans = 0;
F_(i,30,0){
int o = ((x>>i)&1);
if (ch[p][!o]){
p = ch[p][!o];
ans += (1<<i);
} else {
p = ch[p][o];
}
}
return ans;
}
求两个集合中各选一个数异或的最小值
可以枚举第一个集合的数,也可以一次 \(dfs\)
int query(int u,int v,int bit){
int res = 2e9;
if (trie[u][0]&&trie[v][0]) res = min(res,query(trie[u][0],trie[v][0],bit-1));
if (trie[u][1]&&trie[v][1]) res = min(res,query(trie[u][1],trie[v][1],bit-1));
if (res < 2e9) return res;
if (trie[u][0]&&trie[v][1]) res = min(res,(1<<bit)|query(trie[u][0],trie[v][1],bit-1));
if (trie[u][1]&&trie[v][0]) res = min(res,(1<<bit)|query(trie[u][1],trie[v][0],bit-1));
if (res==2e9) res = 0;
return res;
}
可持久化 0-1 Trie
就是运用可持久化线段树的思想
P4735 最大异或和
求后缀不好处理,考虑用前缀和 \(s_n\) 异或一下 \(x\),转换为前缀和,直接上可持久化 0-1 Trie 即可,注意一些细节
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a; i<=b; ++i)
#define F_(i,a,b) for(int i=a; i>=b; i--)
const int N = 6e5+10;
int n,m,tot;
int ar[N],s[N];
int rt[N],cnt[N<<7],ch[N<<7][2];
void update(int p,int pre,int x){
int u = ++tot;
rt[p] = u;
F_(i,25,0){
int o = ((x>>i)&1);
ch[u][o] = ++tot;
ch[u][!o] = ch[pre][!o];
pre = ch[pre][o];
u = ch[u][o];
cnt[u] = cnt[pre]+1;
}
}
int query(int u,int v,int x){
int res = 0;
F_(i,25,0){
int o = ((x>>i)&1);
//cout << cnt[ch[v][!o]]-cnt[ch[u][!o]] << "\n";
if (cnt[ch[v][!o]] > cnt[ch[u][!o]]){
u = ch[u][!o], v = ch[v][!o];
res += (1<<i);
} else {
u = ch[u][o], v = ch[v][o];
}
}
return res;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m;
F(i,1,n){
cin >> ar[i];
s[i] = s[i-1]^ar[i];
update(i,rt[i-1],s[i]);
}
while (m--){
char op; int l,r,x;
cin >> op;
if (op == 'A'){
cin >> x;
++n;
ar[n] = x; s[n] = s[n-1]^ar[n];
update(n,rt[n-1],s[n]);
} else {
cin >> l >> r >> x;
x ^= s[n];
l--, r--;
if (l==0) cout << max(x,query(0,rt[r],x)) << "\n";
else cout << query(rt[l-1],rt[r],x) << "\n";
}
}
return 0;
}
P4098 [HEOI2013] ALO
枚举每个数作为次大值,找出两段极长合法区间,然后就是板子

浙公网安备 33010602011771号