R : [算法竞赛进阶指南]The XOR Longest Path 最长异或路径
Time Limit:2 Sec Memory Limit:128 MiB
Back Submit Edit
Description
[POJ3764]
给定一个树,树上的边都具有权值。
树中一条路径的异或长度被定义为路径上所有边的权值的异或和:
⊕ 为异或符号。
给定上述的具有n个节点的树,你能找到异或长度最大的路径吗?
Input
第一行包含整数n,表示树的节点数目。
接下来n-1行,每行包括三个整数u,v,w,表示节点u和节点v之间有一条边权重为w。
数据规模:
1 ≤ n ≤ 100000,
0 ≤ u,v < n
0 ≤ w < 2^31
Output
输出一个整数,表示异或长度最大的路径的最大异或和。
Sample Input
4
0 1 3
1 2 4
1 3 6
Sample Output
7
More Info
样例中最长异或值路径应为0->1->2,值为7 (=3 ⊕ 4)
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=100010;
int trie[maxn*32][2];//字典树还是存储的整型数据的32位二进制数据
int cnt[maxn];
int a[maxn];
int n,m,idx;
vector<pair<int ,int > >g[maxn];
//g数组用于存储结点的后序结点,以及两结点之间的权重
//注意的是g数组中的每一位数据,也就是每一个结点的数据
//才是一个向量类型,因为一个父结点可能会指向几个不同的子结点
void dfs(int x,int f,int s)
{
a[x]=s;//记录x结点到根结点(这里指0结点)的异或和
for(int i=0;i<g[x].size();i++)
{//循环遍历x结点的所有后序结点
int nxt=g[x][i].first;//获得某一个后序结点
int val=g[x][i].second; //两个结点之间的权重
if(nxt!=f)
dfs(nxt,x,s^val);//为防止无限循环,特判不对父结点进行搜索
}
}
void insert(int num)
{
int p=0;
for(int i=31;~i;i--)
{
int ch=num>>i&1;
int &c=trie[p][ch];
if(!c)c=++idx;
p=c;
}
}
int find(int num)
{
int p=0,sum=0;
for(int i=31;~i;i--)
{
int ch=num>>i&1;
int &c=trie[p][!ch];
if(c)
{
sum+=1<<i;
p=c;
}
else p=trie[p][ch];
}
return sum;
}
int main(){
cin>>n;
for(int i=0;i<n-1;i++)
{ int a,b,c;
scanf("%d %d %d",&a,&b,&c);
g[a].push_back({b,c});
g[b].push_back({a,c});
//分别将a,b两个结点之间的关系存储到各自结点的记录数据中
//这是两个结点都存数据,表明没有明确指出谁是父结点谁是子结点
}
dfs(0,-1,0);//由0结点开始循环
//由于字典树是一个根结点为空的树所以这里假设0结点的父结点为-1
//并且0结点的异或和为0
//因为经过深度优先搜索a数组获得了每个结点到根结点
//(0结点)之间的异或和
//这里若想找到某一条路径的最大异或和
//只需将每个结点的异或和存入字典树
//然后进行最大异或值判断就行了
//以下是最大异或对的判断
for(int i=0;i<n-1;i++)
insert(a[i]);
int maxnn=0;
for(int i=0;i<n-1;i++)
maxnn=max(maxnn,find(a[i]));
cout<<maxnn;
return 0;
}