1. 程式人生 > >Trie樹_POJ3764_The xor-longest Path

Trie樹_POJ3764_The xor-longest Path

點此開啟題目頁面

思路分析:

    根據異或運算滿足結合律和交換律, 且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;
}