题意
一颗树n个节点,每个边有个权值,在树上找一条简单路径,使得这条路径上的边权异或值最大。
题解
前缀异或和+trie
设d[x]=d[fa[x]] xor e[k].c,这样做的好处是可以很方便的求出两点路径上边权的异或值wight(x,y)=d[x] xor d[y]。无论是在同一棵子树还是分散在两棵子树中,都适用。
题意就转换成了求n个数中任取两个数的最大异或值。这是个基本题型,这里不再详细分析,不会的请自学。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int power[40];
int d[maxn];
struct edge
{
int x,y,c,next;
}e[maxn*2];int len,last[maxn];
void ins(int x,int y,int c)
{
e[++len]=(edge){x,y,c,last[x]};last[x]=len;
}
void dfs(int x,int fa)//处理d数组
{
for(int k=last[x];k;k=e[k].next)
{
int y=e[k].y;
if(y==fa) continue;
d[y]=d[x]^e[k].c;
dfs(y,x);
}
}
struct trnode
{
int son[2];
}tr[maxn*32];int trlen;
void insert(int q)
{
int x=0;
for(int i=30;i>=0;i--)
{
if(q>=power[i])
{
q-=power[i];
if(tr[x].son[1]==0)
{
tr[x].son[1]=++trlen;
tr[trlen].son[0]=tr[trlen].son[1]=0;
}
x=tr[x].son[1];
}
else
{
if(tr[x].son[0]==0)
{
tr[x].son[0]=++trlen;
tr[trlen].son[0]=tr[trlen].son[1]=0;
}
x=tr[x].son[0];
}
}
}
int find_max(int q)
{
int x=0,re=0;
for(int i=30;i>=0;i--)
{
if(q>=power[i])//1
{
q-=power[i];
if(tr[x].son[0]!=0)
{
re+=power[i];
x=tr[x].son[0];
}
else if(tr[x].son[1]!=0) x=tr[x].son[1];
}
else//0
{
if(tr[x].son[1]!=0)
{
re+=power[i];
x=tr[x].son[1];
}
else if(tr[x].son[0]!=0) x=tr[x].son[0];
}
}
return re;
}
int main()
{
power[0]=1;for(int i=1;i<=30;i++) power[i]=power[i-1]<<1;
int n;
while(scanf("%d",&n)!=EOF)
{
trlen=len=0;memset(last,0,sizeof(last));
for(int i=1;i<n;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
x++;y++;
ins(x,y,c);ins(y,x,c);
}
d[1]=0;dfs(1,0);
tr[0].son[0]=tr[0].son[1]=0;
int ans=0;
for(int i=1;i<=n;i++)
{
ans=max(ans,find_max(d[i]));//每次只需要在1~i-1中查找最大xor
insert(d[i]);
}
printf("%d\n",ans);
}
return 0;
}