pojThe xor-longest Path(trie树)

本文介绍了一种利用Trie树求解树形结构中任意两点间路径异或值最大化的算法。通过深度优先搜索计算各节点到根节点的异或值,并将这些值存入Trie树中以便快速查询最大的异或配对值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚刚知道一条性质:a^b=(a^c)^(b^c)。于是两点之间的异或值为其分别到根节点的异或值的异或。

用dfs求出每个点到根节点的异或值,并把每个值放在trie树上。注意:要从高位向低位建。

要使异或值最大,异或值为111...1,e.g.10101^01010=11111  ^-^

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define inf 100005
struct node
{
	int to,next,val;
}edge[inf<<1];
int head[inf];
int cnt;
void add(int f,int t,int v)
{
	edge[cnt].to=t;
	edge[cnt].val=v;
	edge[cnt].next=head[f];
	head[f]=cnt++;
}
int n;
int dis[inf],vis[inf];
void dfs(int x,int w)//求每个点到根节点的异或
{
	dis[x]=w;
	vis[x]=1;
	for(int i=head[x];i!=-1;i=edge[i].next)
	{
		int to=edge[i].to;
		if(vis[to])continue;
		dfs(to,w^edge[i].val);
	}
}
struct trie
{
	int next[3];
}t[inf<<8];
int L;
void insert(int x)//建树
{
	int a,p=0;
	for(int i=30;i>=0;i--)
	{
		a=x&(1<<i)?1:0;
		if(!t[p].next[a])//判断这位上有没有出现过这个数
		{
			t[p].next[a]=++L;//新建
			t[L].next[0]=t[L].next[1]=0;//初始化
		}
		p=t[p].next[a];//向下移一位
	}
}
int find(int x)
{
	int a,p=0,w=0;
	for(int i=30;i>=0;i--)
	{
		a=x&(1<<i)?0:1;//我们要找与这一位相反的数
		if(t[p].next[a])
		{
			w|=(1<<i);//找到了就加上
			p=t[p].next[a];
		}else
		{
			p=t[p].next[!a];
		}
	}
	return w;
}
void init()
{
	memset(head,-1,sizeof(head));
	memset(dis,0,sizeof(dis));
	memset(vis,0,sizeof(vis));
	cnt=0;
	L=0;
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		init();
		for(int i=1;i<n;i++)
		{
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			add(a,b,c);
			add(b,a,c);
		}
		dfs(0,0);
		t[0].next[0]=t[0].next[1]=0;
		int ans=0;
		for(int i=0;i<n;i++)
		{
			insert(dis[i]);
			int u=find(dis[i]);
			ans=max(ans,u);
		}
		printf("%d\n",ans);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值