洛谷-4551 最长异或路径

题目描述
给定一棵n个点的带权树,结点下标从1开始到N。寻找树中找两个结点,求最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
输入格式
第一行一个整数N,表示点数。
接下来 n−1 行,给出 u,v,w ,分别表示树上的 u 点和 v 点有连边,边的权值是 w。
输出格式
一行,一个整数表示答案。

输入输出样例
输入 #1
4
1 2 3
2 3 4
2 4 6

输出 #1
7

说明/提示
最长异或序列是1-2-3,答案是 7 (=3 ⊕ 4)
数据范围
1≤n≤100000;0<u,v≤n;0≤w<231

解释:首先利用异或的性质, a ⊕ a = 0 a⊕ a=0 aa=0则我们可以预处理出来点 v v v到树根的异或路径的值, d p [ v ] dp[v] dp[v]
得到 d p [ 1 ] , d p [ 2 ] , . . . , d p [ n ] dp[1],dp[2],...,dp[n] dp[1],dp[2],...,dp[n]后,问题转化成求取两个数异或最大值,很经典的字典树问题,直接上模板

#include<iostream>
#define N 200005
using namespace std;
int head[N]={0};
int nex[N]={0};
int V[N]={0};
int To[N]={0};
int tot=0;
int dp[N]={0};
int n=0;
struct node{
    node *tree[2];
    int v;
};
void free(node *rt){
    if(!rt) return;
    free(rt->tree[0]);free(rt->tree[1]);
    delete(rt);
}
void insert(node *rt,int v,int num){
    if(num>31){
        rt->v=1;
        return;
    }
    int y=(v>>(31-num))&1;
    if(rt->tree[y]==NULL){
        rt->tree[y]=new node;
        rt->tree[y]->tree[0]=rt->tree[y]->tree[1]=NULL;
        rt->tree[y]->v=0;
    }
    insert(rt->tree[y],v,num+1);
}
int query(node *rt,int v){
    int ret=0;
    node *temp=rt;
    for(int i=30;i>=0;i--){
        int y=(v>>i)&1;
        if(temp->tree[!y]){
            ret|=(1<<i);
            temp=temp->tree[!y];
        }else{
            temp=temp->tree[y];
        }
    }
    return ret;
}
node *root=new node;
void add(int x,int y,int v){
    tot++;
    nex[tot]=head[x];
    V[tot]=v;To[tot]=y;
    head[x]=tot;
}
void dfs(int rt,int fa){
    for(int i=head[rt];i;i=nex[i]){
        int to=To[i],v=V[i];
        if(to==fa) continue;
        dp[to]=dp[rt]^v;
        dfs(to,rt);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<n;i++){
        int a,b,c;cin>>a>>b>>c;
        add(a,b,c);add(b,a,c);
    }
    dfs(1,0);
    int ret=0;
    insert(root,dp[1],1);
    for(int i=2;i<=n;i++){
        ret=max(ret,query(root,dp[i]));
        insert(root,dp[i],1);
    }
    free(root);
    cout<<ret<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值