Trie树_POJ3764_The xor-longest Path

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/83865344

点此打开题目页面

思路分析:

    根据异或运算满足结合律和交换律, 且x XOR x = 0, x XOR 0 = x. 考虑选定题目中给定树的一点为树根r, 计算所有点到r的异或路径值, 设点i到根r的异或路径值为a, 点j到点根r的异或路径值为b, 那么点i到点j的异或路径值为a XOR b. 至此, 题目转换为计算若干个数两两异或的最大值问题(参见之前讲解题目CH1602的博文). 具体参见如下AC代码:

//POJ3764_The xor-longest Path
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std; 
const int MAX = 1e5 + 5;
int po[MAX << 1], head[MAX], nex[MAX << 1], weight[MAX << 1], tot;
int xorval[MAX];//点i到根的异或路径值
int trie[MAX * 31 + 5][2], ttot;
//计算点u的所有后代结点到根的路径的异或值
bool calc[MAX]; 
void clacXor(int u){
	for(int i = head[u]; i; i = nex[i]) 
		if(!calc[po[i]]) xorval[po[i]] = xorval[u] ^ weight[i], calc[po[i]] = true, clacXor(po[i]);
}
int main(){
	int n; 
	while(~scanf("%d", &n)){
		memset(calc, false, sizeof(calc)), memset(trie, 0, sizeof(trie));
		memset(nex, 0, sizeof(nex)), memset(head, 0, sizeof(head));
		tot = 0, ttot = 0; 
		for(int i = 1, u, v, w; i < n; ++i){
			scanf("%d %d %d", &u, &v, &w);
			if(!head[u]) head[u] = ++tot, po[tot] = v, weight[tot] = w;
			else po[++tot] = v, nex[tot] = head[u], head[u] = tot, weight[tot] = w;
			if(!head[v]) head[v] = ++tot, po[tot] = u, weight[tot] = w;
			else po[++tot] = u, nex[tot] = head[v], head[v] = tot, weight[tot] = w;
		}		
		calc[0] = true, xorval[0] = 0; clacXor(0);
		//计算xorval[0...n - 1]两两异或的最大值		
		int ans = 0;
		for(int i = 0; i < n; ++i){
			int tans = 0, k = 0;
			for(int j = 30; j >= 0; --j){
				int b = xorval[i] >> j & 1;
				if(trie[k][!b]) k = trie[k][!b], tans |= 1 << j;
				else k = trie[k][b];
			}
			ans = max(ans, tans), k = 0;
			for(int j = 30; j >= 0; --j){
				int b = xorval[i] >> j & 1;
				if(!trie[k][b]) trie[k][b] = ++ttot, k = trie[k][b];
				else k = trie[k][b];
			}
		}
		cout << ans << endl;	
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/solider98/article/details/83865344