01Trie【p4551(poj3764)】 最長異或路徑

題目描述c++

給定一棵 n 個點的帶權樹,結點下標從 1 開始到 N 。尋找樹中找兩個結點,求最長的異或路徑。ui

異或路徑指的是指兩個結點之間惟一路徑上的全部邊權的異或。code

我的get

首先強推一下01字典樹(Trie),這個東西是解決xor問題的利器.數學

查找最大異或值的時候咱們通常從最高位到低位向下找it

eg:   1000(2)=8(10)
         0111(2)=7(10)

顯然只要個人最高位是1,除非你和個人最高位相同,要否則我就是比你大.class

根據數學上的等比數列求和可知
8=2^3 ,7=2^3-1百度

因此說咱們能夠貪心的去找當前位^1的節點query

01字典樹的寫法和trie樹差很少,對於這個題,while

過程:
     1.建圖跑一下再去dfs去求每一個節點到根節點的xor值。
     2.再去構建01Trie去實現咱們的貪心便可

網上講這個的不少,想學的能夠百度

———————代碼—————————

#include<bits/stdc++.h>
#define IL inline
#define RI register int
#define maxn 100008
int trie[maxn*31][2],xo[maxn],ans,rt;
int val[maxn],n,head[maxn],tot;
struct code{int u,v,w;}edge[maxn<<1];
IL void read(int &x){
    int f=1;x=0;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
IL void add(int x,int y,int z)
{
    edge[++tot].u=head[x];
    edge[tot].v=y;
    edge[tot].w=z;
    head[x]=tot;
    edge[++tot].u=head[y];
    edge[tot].v=x;
    edge[tot].w=z;
    head[y]=tot;
}
IL void build_trie(int x,int rt)
{
    for(RI i=1<<30;i;i>>=1)
    {
        bool c=x&i;
        if(!trie[rt][c])trie[rt][c]=++tot;
        rt=trie[rt][c];
    }
}
IL int query(int x,int rt)
{
    int ans=0;
    for(RI i=1<<30;i;i>>=1)
    {
        bool c=x&i;
        if(trie[rt][c^1])ans+=i,rt=trie[rt][c^1];
        else rt=trie[rt][c];
    }
    return ans;
}
IL void dfs(int u,int fa)
{
    for(RI i=head[u];i;i=edge[i].u)
    {
        if(edge[i].v!=fa)
        {
            xo[edge[i].v]=xo[u]^edge[i].w;
            dfs(edge[i].v,u);
        }
    }
}
int main()
{
    read(n);
    for(RI i=1,u,v,w;i<n;i++)read(u),read(v),read(w),add(u,v,w);
    dfs(1,0);
    for(RI i=1;i<=n;i++)build_trie(xo[i],rt);
    for(RI i=1;i<=n;i++)ans=std::max(ans,query(xo[i],rt));
    printf("%d",ans);
}
相關文章
相關標籤/搜索