POJ 3764 The xor-longest Path

本文探讨了利用字典树解决异或路径优化问题的方法,详细介绍了建树逻辑、插入与查询技巧,以及如何通过字典树实现路径的最大异或值计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The xor-longest Path

字典树的题目,开始看的时候毫无头绪,不知道怎么下手,看了别人的解题博客后终于明白了怎么做。这道题目出的很巧妙。之前比赛的时候遇到过一道类似的题目,不过当时我们没做出来,我们队伍还比较弱,还要奋斗啊。大致思路:由于以下式子的成立:(a^b)^(b^c) = c ,所以我们可以这样来建树,每个节点保存从根节点走到当前节点的异或值。然后我们建立一个01字典树。逐个插入每个节点的值(以二进制位方式插入),在插入之前我们先查找一个值,使得这个值是当前已插入字典树的数值中与带插入的值异或最大的。在查询字典树中该数值的时候,我们尽可能的与当前带插入的数值的对应二进制位相反的方向走,这样异或后得到的值肯定会比较大。取出其中比较大的那个异或结果即可。

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std ;

#define maxn 200100

struct Trie{
    int next[2] ;
    int cnt ;
}trie[maxn<<3] ;

int first[maxn] ;//存放节点u的第一条边的编号
int u[maxn] ;
int v[maxn] ;
int w[maxn] ;
int next[maxn] ;//存放下一条边的编号

int ans ;
int n ;
int ncount ;

void add_edge(int x , int y , int z , int e){

    next[e]   = first[x] ;
    first[x]  = e ;

    u[e] = x ;
    v[e] = y ;
    w[e] = z ;
}

void init(){

    memset(first , -1 , sizeof (first) ) ;
    memset(next  , -1 , sizeof (next)  ) ;
    memset(u , 0 , sizeof(u)) ;
    memset(v , 0 , sizeof(v)) ;
    memset(w , 0 , sizeof(w)) ;
    memset(trie , -1 , sizeof (trie) ) ;
    ncount = 0 ;
    ans = 0 ;
}

void cal(int x , int site ,int cnt){
    if(cnt == -1){
        int y = x ^ trie[site].cnt ;
        if(y > ans)
            ans = y ;
    }
    else if(trie[site].next[ (~(x>>cnt)) & 1] != -1){
        cal(x , trie[site].next[ (~(x>>cnt)) &1 ] , cnt - 1) ;
    }
    else
        cal(x , trie[site].next[ (x>>cnt) & 1 ] , cnt - 1 )  ;
}

void insert(int x , int site , int cnt){
    if(cnt != -1){
        if(trie[site].next[ (x>>cnt) & 1 ] == -1){
            trie[site].next[(x>>cnt) & 1] = ++ncount ;
        }
        insert(x , trie[site].next[(x>>cnt) &1] , cnt-1) ;
    }
    else{
        trie[site].cnt = x ;
    }
}

void make(int x ){
    cal(x , 0 , 31) ;
    insert(x , 0 , 31) ;
}

void build_tree(int e , int fa ,int last){
    make(last) ;

    while(e != -1){
        if(v[e] != fa){
            build_tree(first[ v[e] ] , u[e] , last ^ w[e]) ;
        }
        e = next[e] ;
    }
}


bool read(){

    if(scanf("%d" , &n) == EOF){
        return 0 ;
    }

    int x ;
    int y ;
    int z ;
    init() ;

    for(int e = 1 ; e < n ; e ++){
        scanf("%d%d%d" , &x , &y , &z) ;
        add_edge(x , y , z , e) ;
        add_edge(y , x , z , e + n) ;
    }

    return 1 ;
}

void solve(){
    //建树
    build_tree(first[ u[1] ] , -1 , 0) ;
    printf("%d\n" , ans) ;
}

int main(){
    while(read()){
        solve() ;
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值