最长异或和路径

题目详情

最长异或和路径

描述

给定一颗n <= 100 000个点的带权树,求树上最长的异或和路径。

输入

多组数据。每组数据的第一行包含一个整数n(1 <= n <= 100000),以下n -1行每行包含三个整数u(0 <= u < n),v(0 <= v < n) ,w(0 <= w <2 ^ 31),表示u和v之间的长度为w的边。

输出

对于每组数据输出结果。

样例输入

4
1 2 3
2 3 4
2 4 6

样例输出

7

题解

01字典树,先找到每一个结点到根节点的异或和,树上的两个结点i,j之间的异或和就是i点和j点到根节点的异或和异或一下。然后遍历寻找异或和最大。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
typedef pair<int,int>PII;
const int N=1e5+10;
int son[N*32][2],idx;
int a[N];
vector<PII> vec[N];
int n;
int v[N];
//字典树插入模板
void insert(int x)
{
	int p=0;
	for(int i=30;i>=0;i--) {
		int u=x>>i&1;      //转换为二进制的第i位是0还是1
		if(!son[p][u]) son[p][u]=++idx;  //如果插入中发现没有该子节点,开出这条路
		p=son[p][u];        //指针指向下一个点
	}
}
//字典树查询模板,异或最大,即找和第i位相反的
int ask(int x)
{
	int res=0,p=0;
	for(int i=30;i>=0;i--) {
		int u=x>>i&1;
		if(son[p][!u]) {     //和第i位相反的存在
			res+=1<<i;   
			p=son[p][!u];
		}
		else {              //和第i位相反的不存在
			p=son[p][u];
		}
	}
	return res;
}
void bfs(int x) //广搜查找每个结点到根结点的异或和
{
	memset(v,0,sizeof(v));
	queue<int>q;
	q.push(x);
	v[x]=1;
	while(!q.empty()) {
		int u=q.front();
		q.pop();
		insert(a[u]);
		for(int i=0;i<vec[u].size();i++) {
			int t=vec[u][i].first,d=vec[u][i].second;
			if(!v[t]) {
				v[t]=1;
				a[t]=a[u]^d;
				q.push(t);
			}
		}
	}
}
int main()
{
	while(~scanf("%d",&n)) {
		memset(son,0,sizeof(son));
		for(int i=1;i<n;i++) {
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			vec[a].push_back({b,c});
			vec[b].push_back({a,c});
		}
		bfs(1);
		int res=0;
		for(int i=1;i<=n;i++) {
			res=max(res,ask(a[i]));
		}
		printf("%d\n",res);
	}
	
	// system("pause");
	return 0;
}

posted @ 2022-07-20 20:25  海盐味的苏打水  阅读(114)  评论(2编辑  收藏  举报