Loading

P4551-最长异或路径

题意:

在有点权的树上找一条链,使得链上所有点异或和最大。

思路:

  • 树上的异或有这样的性质:两个节点的链的异或和等于两个点分别到根结点的异或和的异或和。于是考虑预处理出所有点到根结点的异或和前缀,作为新的点权。则原问题转化为在所有点中找两个使得其异或和最大。
  • 这是个经典问题,解法:把所有数扔进\(Trie\)​树里,\(Trie\)​树上每个节点维护经过了多少个数,枚举所有数,若当前位为\(0/1\)​则优先向\(1/0\)​查看有没有数经过,跑到最后一位可以找出一个数来更新答案。复杂度\(O(nlogn)\)

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const ll inf=1e15;
const int maxm=5e5+10;
int n,m;
struct node{
    int v;int w;
};
vector<node> yuan[maxn];
int zhi[maxn];
void dfs(int now,int fa,int xo){
    zhi[now]=xo;
    for(int i=0;i<yuan[now].size();i++){
        int v=yuan[now][i].v,w1=yuan[now][i].w;
        if(v==fa) continue;
        dfs(v,now,(xo^w1));
    }
}
struct trie{
    int cha[2];
}all[maxn<<4];
int tot;
void build(int now,int x){
    for(int i=(1LL<<33);i>0;i>>=1LL){
        int c1=((now&i)?1:0);
        if(!all[x].cha[c1]) all[x].cha[c1]=++tot;
        x=all[x].cha[c1];
    }
}
ll req(int now,int x){
    ll ans1=0;
    for(int i=(1LL<<33);i>0;i>>=1LL){
        int c1=((now&i)?1:0);
        if(all[x].cha[!c1]){
            ans1+=i;
            x=all[x].cha[!c1];
        }
        else x=all[x].cha[c1];
    }
    return ans1;
}
signed main(){
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v,w;cin>>u>>v>>w;
        yuan[u].push_back((node){v,w});
        yuan[v].push_back((node){u,w});
    }
    dfs(1,0,0);
    for(int i=1;i<=n;i++) build(zhi[i],0);
    ll ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,req(zhi[i],0));
    cout<<ans<<endl;
    return 0;
}
posted @ 2021-07-21 23:56  14long  阅读(22)  评论(0)    收藏  举报