链接:点击打开链接
题意:给定一棵个点的带权树,结点下标从开始到。寻找树中找两个结点,求最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int siz=100005;
struct node{
ll v,w;
};
vector<node> G[siz];
ll rt,ans,a[35],tr[35*siz][2];
void in(ll x){
ll i,u,pos;
pos=0;
for(i=0;i<35;i++)
a[i]=0;
while(x){
a[pos++]=x&1LL;
x>>=1LL;
}
u=0;
for(i=34;i>=0;i--){
if(tr[u][a[i]]==0)
tr[u][a[i]]=++rt;
u=tr[u][a[i]];
}
}
ll sol(ll x){
ll i,u,v,pos,ans;
pos=0;
for(i=0;i<35;i++)
a[i]=0;
while(x){
a[pos++]=x&1;
x>>=1;
}
u=ans=0;
for(i=34;i>=0;i--){
v=a[i]^1;
if(tr[u][v]!=0){
ans=(ans<<1)|1;
u=tr[u][v];
}
else{
ans<<=1;
u=tr[u][a[i]];
}
}
return ans;
}
void dfs(ll s,ll fa,ll sum){
ll i,v,w;
for(i=0;i<G[s].size();i++){
v=G[s][i].v;
w=G[s][i].w;
if(v==fa)
continue;
ans=max(ans,sol(w^sum));
in(w^sum);
dfs(v,s,w^sum);
}
} //假如求u,v间的异或和,直接用到根节点的异或和异或即可
int main(){ //因为到lca(u,v)到根节点的异或和异或两遍为0,所以
ll n,u,v,w,i; //直接算出每个点到根节点的异或和,然后问题就变成
scanf("%lld",&n); //了n个数中找两个数的最大异或和,直接变成二进制
for(i=1;i<=n;i++) //在trie树上贪心
G[i].clear();
for(i=0;i<n-1;i++){
scanf("%lld%lld%lld",&u,&v,&w);
G[u].push_back((node){v,w});
G[v].push_back((node){u,w});
}
rt=0;
memset(tr,0,sizeof(tr));
in(0);
ans=0;
dfs(1,-1,0);
printf("%lld\n",ans);
return 0;
}