最长异或和路径
题目详情
描述
给定一颗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;
}