AcWing 144 最长异或值路径 (Trie)

题目链接:https://www.acwing.com/problem/content/146/

\(D[i]\) 表示 \(i\) 到根路径上的值的异或之和,
则根据异或的性质,\(u,v\) 间路径的异或和即为 \(D[u] ^ D[v]\)

所以问题就变成了在 \(D\) 中选出异或值最大的两个数
Trie树解决即可

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 3000010;

int n, ans;
int D[maxn];
int root = 0, tot = 0;

int h[maxn], cnt = 0;

struct E{
	int to, next, w;
}e[100010 << 1];

void add(int u, int v, int w){
	e[++cnt].to = v;
	e[cnt].w = w;
	e[cnt].next = h[u];
	h[u] = cnt;
}

struct Trie{
	int son[2];
}trie[maxn];

void insert(int x){
	int pos = root;
	for(int i=31; i>=0; --i){
		int num = ((x >> i) & 1);
		if(!trie[pos].son[num]) trie[pos].son[num] = ++tot;
		pos = trie[pos].son[num];
	}
}

int query(int x){
	int res = 0;
	int pos = root;
	for(int i=31; i>=0; --i){
		int num = ((x >> i) & 1);
		if(trie[pos].son[num ^ 1]){
			pos = trie[pos].son[num ^ 1];
			res ^= (1 << i);
		}else{
			pos = trie[pos].son[num];
		}
	} 
	return res;
}

void dfs(int u, int par){
	for(int i=h[u];i!=-1;i=e[i].next){
		int v = e[i].to, w = e[i].w;
		if(v == par) continue;
		D[v] = D[u] ^ w;
		dfs(v, u);
	}
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
	memset(h, -1, sizeof(h)); ans = 0;
	n = read();
	
	int u, v, w;
	for(int i=1;i<n;++i){
		u = read(), v = read(), w = read();
		++u, ++v;
		add(u, v, w);
		add(v, u, w);
	}
	
	D[1] = 0;
	dfs(1, 0);
	
	insert(D[1]);
	for(int i=1;i<=n;++i){
		ans = max(ans, query(D[i]));
		insert(D[i]);
	}
	
	printf("%d\n", ans);
	
	return 0;
}
posted @ 2020-11-08 15:52  Tartarus_li  阅读(66)  评论(0编辑  收藏  举报