字典树

字典树(Trie)

支持 \(O(|s|)\) 插入/查询一个字符串。空间复杂度为 \(O(|s|_{\max}|\Sigma|)\)

01 Trie

\(\Sigma=\{0,1\}\) 的字典树,类似二进制,插入/查询一个数复杂度为 \(O(\log x)\)。空间复杂度貌似是 \(O(\log x)\) 的?

这种数据结构可以用来维护异或等基本操作,由于不需要递归,所以常数会小些。

维护异或极值

例:P4551 最长异或路径

给你一棵树,树上每个点有点权,求 \((u,v)\) 满足路径上的边权异或值最大。
\(n\le 10^5,w\in[0,2^{31})\)

\(X(u,v)\)\((u,v)\) 路径上的异或和,钦定 1 为根。考虑异或有性质 \(X(u,v)=X(u,1)\oplus X(v,1)\),考虑记下每个 \(X(u,1)\) 并插入 01 Trie,然后对于每个 \(u\),从 01 Trie 的根开始找尽量与 \(X(u,1)\) 当前位不同的位跑,直到走到底。显然越高位的贡献越大(\(2^{x}>2^{x-1}+2^{x-2}+\ldots+1\)),所以贪心正确。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+3;
struct edge{
    int v,w;
};
vector<edge>e[maxn];
int trie[maxn*32][2],n,node;
int xo[maxn];
void insert(int v,int x){
    int u=0;
    for(int i=31;~i;i--){
        if(!trie[u][(x>>i)&1])
            trie[u][(x>>i)&1]=++node;
        u=trie[u][(x>>i)&1];
    }
    xo[v]=x;
}
void dfs(int u,int fa,int x){
    insert(u,x);
    for(edge v:e[u])
        if(v.v!=fa) dfs(v.v,u,x^v.w);
}
int find(int v){
    int u=0,ans=0;
    for(int i=31;~i;i--){
        if(trie[i][(xo[v]>>i)&1^1]) u=trie[i][(xo[v]>>i)&1^1],ans+=(1<<i);
        else if(trie[i][(xo[v]>>i)&1]) u=trie[i][(xo[v]>>i)&1];
        else break;
    }
    return ans;
}
signed main(){
    cin>>n;     
    for(int i=1,u,v,w;i<n;i++){
        cin>>u>>v>>w;
        e[u].push_back({v,w});
        e[v].push_back({u,w});
    }
    dfs(1,0,0);
    int ans=0;
    for(int i=1;i<=n;i++)
        ans=max(ans,find(i));
    cout<<ans;
    return 0;
}
posted @ 2024-10-30 09:36  view3937  阅读(2)  评论(0编辑  收藏  举报
Title