最长异或路径【Trie】

>Link

luogu P4551

ybtoj最长异或路径


>Description

给定一棵 N 个点的带权树,结点下标从 1 到 N。求树上最长的异或路径。

异或路径指的是指两个结点之间唯一路径上的所有边权的异或。

1 ≤ n ≤ 1 0 5 , 0 ≤ w < 2 31 1≤n≤10^5,0≤w<2^{31} 1n105,0w<231


>解题思路

我们可以预处理根节点到第 i i i个节点的路径上的异或和 a i a_i ai
那根据异或的性质, u u u v v v的异或路径就为 a u ⊕ a v a_u⊕a_v auav
那这道题就跟最大异或对一样了

注意:因为 0 ≤ w < 2 31 0≤w<2^{31} 0w<231,所以我们就默认每个 a i a_i ai长度为31来处理,不然暴力找最长的 a i a_i ai长度然后再处理的话很容易出一些错误
(主要是懒得调QwQ


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;

struct edge
{
    
    
	int to, nxt, w;
} e[N * 2];
int n, cnt, h[N], a[N], t[N * 30][5], tot;
int sum, ans;

void add (int u, int v, int w)
{
    
    
	e[++cnt] = (edge){
    
    v, h[u], w}; h[u] = cnt;
	e[++cnt] = (edge){
    
    u, h[v], w}; h[v] = cnt;
}
void dfs (int now, int fath)
{
    
    
	for (int i = h[now]; i; i = e[i].nxt)
	{
    
    
		int v = e[i].to;
		if (v == fath) continue;
		a[v] = a[now] ^ e[i].w;
		dfs (v, now);
	}
}

int main()
{
    
    
	int u, v, w;
	scanf ("%d", &n);
	for (int i = 1; i < n; i++)
	{
    
    
		scanf ("%d%d%d", &u, &v, &w);
		add (u, v, w);
	}
	dfs (1, 0);
	int k, now, x;
	for (int i = 1; i <= n; i++)
	{
    
    
		now = 0;
		for (int j = 1; j <= 31; j++)
		{
    
    
			x = (a[i] >> (31 - j)) & 1;
			if (!t[now][x]) t[now][x] = ++tot;
			now = t[now][x];
		}
	}
	for (int i = 1; i <= n; i++)
	{
    
    
		now = sum = 0;
		k = 1 << (31 - 1);
		for (int j = 1; j <= 31; j++)
		{
    
    
			x = (a[i] >> (31 - j)) & 1;
			if (t[now][x ^ 1])
			{
    
    
				sum += k;
				now = t[now][x ^ 1];
			}
			else now = t[now][x];
			k >>= 1;
		}
		ans = max (ans, sum);
	}
	printf ("%d", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/120908448