题意
给定一个有n个节点的树,每条边上有个边权,从树中任选两个节点 x 和 y ,把 x 到 y 的路径上所有边权xor起来,求最大值
分析
xor???有意思,还记得异或的自反性吗(a^b^b=a,a^0=a)
我们发现若将 x 到根路径上的所有边权异或起来,记作 d[x];y 到根路径上的所有边权异或起来,记作 d[y]
那么 d[x] xor d[y] 就是 x 到 y 的路径上所有边权xor起来的值
为什么呢?
因为 x 到根路径上(假设dep[x]>dep[y])和 y 到根路径上重复的边,在xor的时候就没了(异或两次相当于没有异或)
那我们就可以预处理出所有的 d[i]
然后现在问题就转化为求序列d[1]~d[n]中任意两个数异或起来的最大值
就可以用上一篇博客的方法了
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100009
#define in read()
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
int n,d[N];
int nxt[N<<1],head[N],to[N<<1],w[N<<1],cnt=0;
void add(int x,int y,int z){
nxt[++cnt]=head[x];head[x]=cnt;
to[cnt]=y;w[cnt]=z;
}
void dfs(int u,int fu){
for(int e=head[u];e;e=nxt[e]){
int v=to[e];
if(v==fu) continue;
d[v]=(d[u]^w[e]);
dfs(v,u);
}
}
int trie[N<<5][2],tot=0;
void insert(int x){
int pos=0;
for(int i=31;i>=0;--i){
int c;
if(x&(1ll<<i)) c=1;
else c=0;
if(!trie[pos][c]) trie[pos][c]=++tot;
pos=trie[pos][c];
}
}
int query(int x){
int pos=0,res=0;
for(int i=31;i>=0;--i){
int c;
if(x&(1ll<<i)) c=1;
else c=0;
if(trie[pos][c^1]) pos=trie[pos][c^1],res=res|(1ll<<i);
else pos=trie[pos][c];
}
return res;;
}
int main(){
while(scanf("%d",&n)!=EOF){
int i,j,k;
cnt=0;memset(head,0,sizeof(head));
memset(trie,0,sizeof(trie));tot=0;
memset(d,0,sizeof(d));
for(i=1;i<n;++i){
int u,v,w;
u=in;v=in;w=in;
u++;v++;
add(u,v,w);add(v,u,w);
}
dfs(1,0);
int maxn=-1;
for(i=1;i<=n;++i){
maxn=max(maxn,query(d[i]));
insert(d[i]);
}
printf("%d\n",maxn);
}
return 0;
}