POJ 3764 The xor-longest Path

求异或最大值。。题目意思有点难懂尴尬

多亏纬哥解释 题目 和 做法 给我听。。

真是一道好题啊(但感觉测试数据还是水了一点)。。感觉对trie树更加理解了。。

我们知道异或有这样的性质:a^b = (a^c)^(b^c),这样就可以考虑找出a与b公共的c,实际上就是求出从根节点到每个节点的异或值,这样任意两个点做异或,即是他们之间的异或路径(相同部分异或抵消了)。可以dfs遍历一遍。

然后可以用字典树来储存每个节点的值,问题又转化成求这n个数中,任意两个数做异或,求最大值。每插入字典树一次,更新最大值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
using namespace std;
#define mod 100000007
#define eps 1e-8
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f3f
#define mnx 200020
int first[mnx], vv[mnx], cost[mnx], nxt[mnx], d[mnx], cnt;
bool vis[mnx];
int str[50], son[mnx*16][2], val[mnx*16];
void insert( int s ){
	int tem = s;
	for( int i = 1; i <= 31; i++ ){
		str[i] = tem%2;   tem /= 2;
	}
	int t = 0;
	for( int i = 31; i >= 1; i-- ){
		int c = str[i];
		if( son[t][c] == 0 ){
			son[t][c] = ++cnt;
			son[cnt][0] = son[cnt][1] = 0;
			val[cnt] = 0;
		}
		t = son[t][c];
	}
	val[t] = s;
}
int find( int s ){
	int tem = s;
	for( int i = 1; i <= 31; i++ ){
		str[i] = tem%2;   tem /= 2;
	}
	int t = 0;
	for( int i = 31; i >= 1; i-- ){
		int c = str[i];
		if( son[t][1-c] )
			t = son[t][1-c];
		else
			t = son[t][c];
	}
	return val[t] ^ s;	
}
void add( int u, int v, int c ){
	vv[cnt] = v;
	cost[cnt] = c;
	nxt[cnt] = first[u];
	first[u] = cnt++;
}
void dfs( int s ){
	vis[s] = 1;
	for( int i = first[s];  i != -1; i = nxt[i] ){
		int v = vv[i];
		if( !vis[v] ){
			d[v] = cost[i] ^ d[s];
			dfs(v);
		}
	}
}
void init(){
	son[0][0] = son[0][1] = val[0] = 0;
	memset(first, -1, sizeof(first));
	memset(vis, 0, sizeof(vis));
	cnt = 0;
}
int main(){
	int n;
	while( scanf("%d", &n) != EOF ){
		init();
		int u, v, c;
		for( int i = 0; i < n-1; i++ ){
			scanf("%d%d%d", &u, &v, &c);
			add(u, v, c);
			add(v, u, c);             //建立邻接表 
		}
		d[0] = 0;
		dfs(0);                      //求出从根节点到每个节点的异或值 
		cnt = 0;
		insert(0);                   //初始化字典树 
		int ans = 0;
		for( int i = 1; i < n; i++ ){
			insert(d[i]);
			ans = max(ans, find(d[i]));  //每插入字典树一次,更新最大值
		}
		printf("%d\n", ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值