The xor-longest Path poj3764

3764 -- The xor-longest Path

题目大意:有一棵n个点的树,树上每条边都有边权,求任意两点之间的简单路径的边权的异或和最大是多少

1<=n<=1e5

思路:因为异或和可以忽略重合的部分,所以两个点之间的路径的异或和就是每个点到他们的公共组先的异或和,那么我们直接从第一个节点出发dfs记录每一个点i(包括第一个点)到第一个点的异或和dx[i],然后我们只需要在所有的dx中找出异或值最大的两个点,用字典树可以做到O(n),trie[i][j]表示二进制从左到右忽略公共前缀的第i位数字是j,对于一个要查询的dx[i],我们在字典树中优先查找与每一位数相反的前缀,得到的便是最大值

边权树如上图,可得出0到各点的异或和dx为0,7,5

字典树(2的0次方到2次方部分)如上图

#include<__msvc_all_public_headers.hpp>//vs代码
using namespace std;
const int N = 1e5 + 5;
int head[N],trie[N*32][2];
int n, dx[N];
struct node
{
	int v, next, w;
}e[N << 1];
int cnt = 0;
void addedge(int u, int v, int w)
{//链式前向星存图
	e[++cnt].v = v;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt;
}
void init()
{
	memset(e, 0, sizeof e);
	memset(head, 0, sizeof head);
	memset(trie, 0, sizeof trie);
	memset(dx, 0, sizeof dx);
}
void dfs(int u, int fa)
{//遍历每个点,求出每个点到0点的异或和
	for (int i = head[u]; i; i = e[i].next)
	{
		int v = e[i].v, w = e[i].w;
		if (v == fa)//防止重复遍历
			continue;
		dx[v] = dx[u] ^ w;
		dfs(v, u);
	}
}
int tot = 1;
void build(int num)
{//构建字典树
	int p = 1;
	for (int i = 30; i >= 0; i--)//数据范围0~2^31
	{
		bool k = num & (1 << i);//判断二进制的每一位为0或1
		if (!trie[p][k])
			trie[p][k] = ++tot;
		p = trie[p][k];
	}
}
int query(int num)
{//对于每个dx[i],求出他和其他所有数异或的最大值
	int p = 1, ret = 0;
	for (int i = 30; i >= 0; i--)
	{
		bool k = num & (1 << i);
		if (trie[p][k ^ 1])//如果这一位有与当前查询数字相反的,优先走这条路
		{
			ret += 1 << i;//答案+
			p = trie[p][k ^ 1];
		}
		else
		{
			p = trie[p][k];
		}
	}
	return ret;
}
int main()
{
	while (~scanf_s("%d", &n))
	{
		init();
		for (int i = 1; i <= n - 1; i++)
		{
			int u, v, w;
			scanf_s("%d%d%d", &u, &v, &w);
			addedge(u, v, w);
			addedge(v, u, w);
		}
		dfs(0, 0);
		for (int i = 0; i <= n - 1; i++)
		{
			build(dx[i]);
		}
		int ans = 0;
		for (int i = 0; i <= n - 1; i++)
		{
			ans = max(ans, query(dx[i]));//维护答案最大值
		}
		printf("%d\n", ans);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timidcatt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值