NCSTOJ:[算法竞赛进阶指南]The XOR Longest Path 最长异或路径

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;
	 
	
	
	
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值