最长路径异或和

题目大意

给定一棵边权树, 要求一条两个点之间的最短路径, 使得路径上所有边的权值的异或最大.

题解

考虑异或的性质:

  • 交换律\(a \oplus b = b \oplus a\)
  • 结合律\((a \oplus b) \oplus c = a \oplus (b \oplus c)\)
  • 消去率\(a \oplus b = a \oplus c \oplus b \oplus c\)

所以我们发现, 假设\(anc\)\(u\)\(v\)的祖先, \(u\)\(v\)分别是路径的两端, 则\(u \to anc \to v = (root \to anc \to u) \oplus (root \to anc \to v)\)

DFS一次, 到达每个点的时候都在trie树上找最大异或值即可.

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>

const int N = (int)1e5;

namespace Zeonfai
{
	inline int getInt()
	{
		int a = 0, sgn = 1;
		char c;
		while(! isdigit(c = getchar()))
			if(c == '-')
				sgn *= -1;
		while(isdigit(c))
			a = a *10 + c - '0', c = getchar();
		return a * sgn;
	}
}

struct trieTree
{
	struct node
	{
		node *suc[2];

		inline node()
		{
			suc[0] = suc[1] = NULL;
		}
	};
	
	node *rt, *lst;

	inline void initialize()
	{
		rt = new node;
	}

	inline void _insert(int k)
	{
		node *u = lst->suc[k];
		if(lst->suc[k] == NULL)
			lst->suc[k] = new node;
		lst = lst->suc[k];
	}
	
	inline void insert(int w)
	{
		lst = rt;
		for(int i = 30; ~ i; -- i)
			_insert(w >> i & 1);
	}

	inline int query(int w)
	{
		int res = 0;
		node *u = rt;
		for(int i = 30; ~ i; -- i)
		{
			int k = w >> i & 1;
			if(u->suc[k ^ 1] != NULL)
				u = u->suc[k ^ 1], res += 1 << i;
			else
				u = u->suc[k];
		}
		return res;
	}
}trie;

int ans = 0;

struct tree
{	
	struct edge
	{
		int v, w, nxt;
	}edg[N << 1];
	
	int tp;
	int hd[N + 1];
	
	inline void initialize()
	{
		tp = 0;
		memset(hd, -1, sizeof(hd));
	}
	
	inline void addEdge(int u, int v, int w)
	{
		edg[tp].v = v, edg[tp].w = w, edg[tp].nxt = hd[u];
		hd[u] = tp ++;
	}
	
	inline void DFS(int u, int pre, int w)
	{
		trie.insert(w);
		ans = std::max(ans, trie.query(w));
		for(int p = hd[u]; ~ p; p = edg[p].nxt)
			if(edg[p].v ^ pre)
				DFS(edg[p].v, u, w ^ edg[p].w);
	}
}org;

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("XSY2340.in", "r", stdin);
	#endif
	using namespace Zeonfai;
	int n = getInt();
	org.initialize();
	for(int i = 1; i < n; ++ i)
	{
		int u = getInt(), v = getInt(), w = getInt();
		org.addEdge(u, v, w), org.addEdge(v, u, w);
	}
	trie.initialize();
	org.DFS(1, -1, 0);
	printf("%d\n", ans);
}
posted @ 2017-07-04 09:02  Zeonfai  阅读(430)  评论(0编辑  收藏  举报