[01trie][思维]The xor-longest Path POJ3764

Description

In an edge-weighted tree, the xor-length of a path p is defined as the xor sum of the weights of edges on p:

⊕ is the xor operator.

We say a path the xor-longest path if it has the largest xor-length. Given an edge-weighted tree with n nodes, can you find the xor-longest path?  

Input

The input contains several test cases. The first line of each test case contains an integer n(1<=n<=100000), The following n-1 lines each contains three integers u(0 <= u < n),v(0 <= v < n),w(0 <= w < 2^31), which means there is an edge between node u and v of length w.

Output

For each test case output the xor-length of the xor-longest path.

Sample Input

4
0 1 3
1 2 4
1 3 6

Sample Output

7

Hint

The xor-longest path is 0->1->2, which has length 7 (=3 ⊕ 4)

题意: 给出一颗带权树,求一条路径,使路径上边权异或值最大。

分析: 考虑如何快速得到路径上边权的异或值。可以任取一点为根,num数组记录各点到根节点的边权异或值,若想得到两节点x,y之间路径上的异或值,只需要num[x]^num[y],因为两点到根节点经过的重复路径被异或了两遍变成了0,因此异或值就是两点间路径的边权异或值。这样问题就转化为在集合内找到两数使它们的异或值最大,就变成了01字典树的模板题了。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
//用num数组记录根到每个节点的异或距离,之后放入trie树求两点间最大异或距离 
int n, cnt, head[100005], son[3200005][2], idx, num[100005];
struct edges
{
	int to, next, w;
}edge[200005];

void init()
{
	for(int i = 0; i <= n-1; i++)
		head[i] = 0;
	cnt = idx = 0;
	memset(son, 0, sizeof son);
}

void add(int u, int v, int w)
{
	edge[++cnt].to = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt;
}

void dfs(int now, int fa)
{
	for(int i = head[now]; i; i = edge[i].next)
	{
		int to = edge[i].to, w = edge[i].w;
		if(fa == to)
			continue;
		num[to] = num[now]^w;
		dfs(to, now);
	}
}

void insert(int x)
{
	int now = 0;
	for(int i = 30; i >= 0; i--)
	{
		int t = (x>>i)&1;
		if(!son[now][t])
			son[now][t] = ++idx;
		now = son[now][t];
	}
}

int query(int x)
{
	int now = 0, temp = 0;
	for(int i = 30; i >= 0; i--)
	{
		int t = (x>>i)&1;
		if(!son[now][!t])
		{
			now = son[now][t];
			temp |= (t<<i); 
		}
		else
		{
			now = son[now][!t];
			temp |= ((!t)<<i);
		}
	}
	return temp^x;
}

signed main()
{
	while(cin >> n)
	{
		init();
		int u, v, w;
		for(int i = 1; i <= n-1; i++)
		{
			scanf("%d%d%d", &u, &v, &w);
			add(u, v, w);
			add(v, u, w);
		}
		dfs(0, -1);
		int ans = 0;
		for(int i = 0; i <= n-1; i++)
		{
			insert(num[i]);
			ans = max(ans, query(num[i]));
		}
		printf("%d\n", ans);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值