【Luogu P4551】最长异或路径

链接:

洛谷

题目大意:

给定一棵 \(n\) 个点的带权树,结点下标从 \(1\) 开始到 \(n\)。寻找树中找两个结点,求最长的异或路径。

正文:

01Trie 板子题。将每个点到根节点的异或和预处理出来,从高位到低位丢到 01Trie 里,查询时反着搜索,因为要使得异或值最大,当前位要尽量取反。

代码:

const int N = 1000010;

int n, head[N];
int tot;
struct edge
{
	int to, val, nxt;
}e[N << 1];

void add(int u, int v, int w) {e[++tot] = (edge){v, w, head[u]}, head[u] = tot;} 

struct Trie
{
	int ch[N][2];
	int siz[N], tot;
	void Ins(ll val)
	{
		int u = 0;
		for (int i = 31; ~i; --i)
		{
			int k = (val >> i) & 1; siz[u] ++;
			if (!ch[u][k]) ch[u][k] = ++ tot;
			u = ch[u][k];
		}
	}
	ll Query(int n, ll val)
	{
		int u = 0; ll ans = 0;
		for (int i = 31; ~i; --i)
		{
			int k = (val >> i) & 1;
			if (!ch[u][k ^ 1]) u = ch[u][k];
			else if (n <= siz[ch[u][k ^ 1]]) u = ch[u][k ^ 1], ans |= 1 << i;
			else n -= siz[ch[u][k ^ 1]], u = ch[u][k];
		}
		return ans;
	}
}t;

ll sum[N], ans;

void dfs (int u, int fa)
{
	for (int v, i = head[u]; i; i = e[i].nxt)
	{
		if ((v = e[i].to) == fa) continue;
		sum[v] = e[i].val ^ sum[u];
		dfs (v, u);
	}
}

int main()
{
	scanf ("%d", &n);
	for (int i = 1, u, v, w; i < n; i++)
	{
		scanf ("%d%d%d", &u, &v, &w);
		add(u, v, w);add(v, u, w);
	}
	dfs(1, -1);
	for (int i = 1; i <= n; i++)
		t.Ins(sum[i]);
	for (int i = 2; i <= n; i++)
		ans = max(ans, t.Query(0, sum[i]));
	printf ("%lld\n", ans);
	return 0;
}
posted @ 2021-03-06 10:01  Jayun  阅读(46)  评论(0编辑  收藏  举报