最长异或值路径

最长异或值路径

给出一棵有n个节点的树,设(w[i][j])为i,j之间的边权,定义一条路径的距离,为这条路径上所有边权的异或和,请你选出任意两个点,最小化这两点之间的路径距离,并求出这个最大值,(1≤n≤100000)

树的问题,无根变有根,更加好研究,通常维护出每个节点到根节点的信息,于是设(s[i])表示点i到根节点的路径的权值的异或和,这个一遍dfs就可以维护出来,我不再赘诉了。

此时发现对于任意两个点i,j之间的距离就变成(w[i]wedge w[j]),原因在于相同的数异或相同的数结果为0,而(w[i]wedge w[j]),恰好因为这个性质,除去了i,j最近公共祖先到根节点的距离,剩下的距离自然都是i,j的距离了。

于是现在问题变成从集合({w[i]})选出两个数,最大化它们的异或和,显然我们只要维护一棵trie树,将这些数当做01串从高位到低位插入trie树,然后对于每个数从trie树从上往下尽量选择让该数的这一位不为0的数字即可。

参考代码:

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define Size 100050
using namespace std;
struct point{
	point *next;int to,w;
}*pt,*head[Size];
bool is[Size];
int dis[Size],trie[Size*31][2],tot;
void dfs(int);
il int ask(int);
il void read(int&),
	link(int,int,int),
	insert(int);
template<class free>
il free Max(free,free);
int main(){
	int n,ans(0);read(n);
	for(int i(1),u,v,w;i<n;++i)
		read(u),read(v),read(w),
			link(u,v,w),link(v,u,w);dfs(0);
	for(int i(1);i<=n;++i)
		ans=Max(ans,ask(dis[i]));
	printf("%d",ans);
	return 0;
}
template<class free>
il free Max(free a,free b){
	return a>b?a:b;
}
il int ask(int x){
	int ans(0),p(0);
	for(int i(30);i>=0;--i)
		if(trie[p][x>>i&1^1])
			p=trie[p][x>>i&1^1],
				ans|=1<<i;
		else p=trie[p][x>>i&1];
	return ans;
}
il void insert(int x){int p(0);
	for(int i(30);i>=0;--i){
		if(!trie[p][x>>i&1])
			trie[p][x>>i&1]=++tot;
		p=trie[p][x>>i&1];
	}
}
void dfs(int x){is[x]|=true,insert(dis[x]);
	for(point *i(head[x]);i!=NULL;i=i->next){
		if(is[i->to])continue;
		dis[i->to]=dis[x]^i->w,dfs(i->to);
	}
}
il void link(int u,int v,int w){
	pt=new point{head[u],v,w},head[u]=pt;
}
il void read(int &x){
	x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/11248071.html