[POJ3764]最长异或路径

Description:

给定一棵n个点的带权树,结点下标从1开始到N。寻找树中找两个结点,求最长的异或路径。

Hint:

\(n<=10^5\)

Solution:

真是01Trie傻逼题,居然想了好久
瓶颈在于如何找出所有的点到根节点的异或值中异或起来最大的两个
考虑将每个点到根节点的异或值插入Trie,再同样地查询一次就行了

#include<bits/stdc++.h>
using namespace std;
const int mxn=1e7+5;
struct ed {
    int to,nxt,w;
}t[mxn<<1];
int n,cnt,a[mxn],hd[mxn];

inline void add(int u,int v,int w) {
    t[++cnt]=(ed) {v,hd[u],w}, hd[u]=cnt;
}

namespace trie {
    int tot,ch[mxn][2];
    void ins(int x) {
        int u=0;
        for(int i=30;i>=0;--i) {
            int is=x>>i&1;
            if(!ch[u][is]) ch[u][is]=++tot;
            u=ch[u][is];
        }
    }
    int query(int x) {
        int u=0,ans=0;
        for(int i=30;i>=0;--i) {
            int is=(x>>i&1)^1;
            if(ch[u][is]) u=ch[u][is],ans+=1<<i;
            else u=ch[u][is^1];
        }
        return ans;
    }
}
using namespace trie;

void dfs(int u,int fa,int w) 
{
    a[u]=w;
    for(int i=hd[u];i;i=t[i].nxt) {
        int v=t[i].to;
        if(v==fa) continue ;
        dfs(v,u,w^t[i].w);
    }
}

int main()
{
    scanf("%d",&n); int u,v,w;
    for(int i=1;i<n;++i) {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    dfs(1,0,0); int ans=0;
    for(int i=1;i<=n;++i) ins(a[i]);
    for(int i=1;i<=n;++i) ans=max(ans,query(a[i]));
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/list1/p/10425983.html