【POJ3764】The xor-longest Path Trie树+异或性质

#include <stdio.h>
int main()
{
	puts("转载请注明出处[vmurder]谢谢");
	puts("网址:blog.csdn.net/vmurder/article/details/43486733");
}


题意:

多组数据、

给你一颗树,

然后求一条最长异或路径,

异或路径长度定义为两点间简单路径上所有边权的异或和。


题解:

首先无根树转有根树再在树上跑一遍算出每个点到根的异或和。

然后两点间异或路径长度就是a[i]*a[j]。

因为lca之前那一段都被异或了两次搞没了。


然后求个线性基,然后随便搞搞就可以?可以WA了!

因为那么算哪是简单路径啊,或者说,那特喵的是什么玩意啊。


嗯,写个Trie树,然后详情可以看我这篇博客。

【JDFZOJ】最富有的人 Trie树+异或性质

诶?这篇博客什么也没说?


好吧,我补个题解:

Trie里面记录每个节点权值的二进制串,

比如5,我们不记录“101”,而是记录“00000……000101”


这样Trie树建好了以后我们枚举一个节点,然后用这个节点在Trie树中找它的最长异或路径长度。

这个时候我们在Trie树上跑,每一位都取反以保证这位尽量是1

然后走不了再取同。


所有最长中取个最大值作为答案

这样就在nlogn时间内得到了解。


详见代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101000
#define LOGN 32
#define T 2
#define inf 0x3f3f3f3f
using namespace std;
int src[N],n;
struct Trie
{
	int son[N*LOGN][T],cnt;
	void init()
	{
		memset(son,0,sizeof son);
		cnt=0;
	}
	void insert(int a)
	{
		int i,x=0,alp;
		for(i=31;i>=0;i--)
		{
			alp=(a>>i)&1;
			if(!son[x][alp])son[x][alp]=++cnt;
			x=son[x][alp];
		}
	}
	int find(int a)
	{
		int i,x=0,alp;
		int ret=0;
		for(i=31;i>=0;i--)
		{
			alp=!((a>>i)&1);
			ret<<=1;
			if(son[x][alp])
			{
				x=son[x][alp];
				ret++;
			}
			else x=son[x][!alp];
		}
		return ret;
	}
}trie;
struct KSD
{
	int v,len,next;
}e[N<<1];
int head[N],cnt;
void init()
{
	cnt=0;
	memset(src,0,sizeof src);
	memset(head,0,sizeof head);
	trie.init();
}
inline void add(int u,int v,int len)
{
	e[++cnt].v=v;
	e[cnt].len=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}
void dfs(int x,int p)
{
	int i,v;
	for(i=head[x];i;i=e[i].next)
	{
		v=e[i].v;
		if(v==p)continue;
		src[v]=src[x]^e[i].len;
		dfs(v,x);
	}
	return ;
}
int main()
{
	freopen("test.in","r",stdin);
	int i,j,k;
	int a,b,c;

	while(scanf("%d",&n)!=EOF)
	{
		init();
		for(i=1;i<n;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			add(a+1,b+1,c),add(b+1,a+1,c);
		}
		dfs(1,0);
		int ans=0;
		for(i=1;i<=n;i++)trie.insert(src[i]);
		for(i=1;i<=n;i++)ans=max(ans,trie.find(src[i]));
		printf("%d\n",ans);
	}
	
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值