这题可以说就是cf888g改编了一下,加上有人赛中发题解,所以过了一百多人,实际上还是很难的
首先我们要先明确一个东西:这个图任意两个点u,v边权值始终不变,因为它所在的环异或和始终等于0,所以,边uv的值就是这个环其他边的异或和,现在即使它所在的环的某条边x被删去了,由于图要联通,那x肯定是被它所在的另一个环的其他边代替,而这些边的异或和等于x的值,这其实相当于没有删x,uv这条边还是在一个同样的环里,权值必然不会变
现在我们就可以将每个点的值变成根节点到他的路径异或和,uv连边,边值就是u点到v点路径异或和,现在可以将原图视为一个完全图,uv边值就是a[u]^a[v],我们最后还是要得到一颗树,所以我们就是求这个完全图的最小生成树
这其实就是cf888g,可以参考我的另一篇博客
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string>
#include<string.h>
#include<map>
#define ll long long
#include <iostream>
#include <math.h>
using namespace std;
#define maxn 3300000+5
ll tre[maxn][3],pos=0,sum[maxn];
struct node
{
ll to,w;
};
vector<node>e[105000];ll a[maxn];
void add(ll x)
{
ll c=0;
for(ll i=30;i>=0;i--)
{
ll y=(x>>i)&1ll;
if(!tre[c][y]) tre[c][y]=++pos;
c=tre[c][y];
sum[c]++;
}
}
ll Find(ll x,ll y,ll step)
{
ll ans=1e18;
if(step==-1) return 0;
if(tre[x][0])
{
if(tre[y][0])//也就是说,尽量保证左右两边数每位尽量一致,这样一致异或就是0
{
ll w=Find(tre[x][0],tre[y][0],step-1);
ans=w;
}
else
{
ll w=Find(tre[x][0],tre[y][1],step-1);
ans=w+(1ll<<step);
}
}
if(tre[x][1])
{
if(tre[y][1])//也就是说,尽量保证左右两边数每位尽量一致,这样一致异或就是0
{
ll w=Find(tre[x][1],tre[y][1],step-1);
ans=min(ans,w);
}
else
{
ll w=Find(tre[x][1],tre[y][0],step-1);
ans=min(ans,w+(1ll<<step));
}
}
//printf("tre[%lld][0]=%lld tre[%lld][1]=%lld tre[%lld][0]=%lld tre[%lld][1]=%lld step=%lld ans=%lld\n",x,tre[x][0],x,tre[x][1],y,tre[y][0],y,tre[y][1],step,ans);
return ans;
}
ll dfs(ll c,ll step)
{
ll ans=0;
ll ls=sum[tre[c][0]],rs=sum[tre[c][1]];
if(step==-1) return 0;
if(tre[c][0])ans+=dfs(tre[c][0],step-1);
if(tre[c][1])ans+=dfs(tre[c][1],step-1);
if(min(ls,rs)>0)//只有0和1都有才会分开连边
{
ans+=Find(tre[c][0],tre[c][1],step-1)+(1ll<<step);//说明0和1都有,那它们0集合就要和1集合连边,这条边贡献1<<step
//然后再在左右子树找一个点对(也就是剩余部分),它们异或和最小
}//printf("step=%lld tre[%lld][0]=%lld tre[%lld][1]=%lld ls=%lld rs=%lld ans=%lld\n",step,c,tre[c][0],c,tre[c][1],ls,rs,ans);
return ans;
}
void init()
{
pos=0;
}
void dfs0(ll u,ll fa)
{
for(node i:e[u])
{
ll v=i.to,w=i.w;
if(v==fa) continue;
a[v]=a[u]^w;
dfs0(v,u);
}
}
int main()
{
/*ll n;
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
ll x;
scanf("%lld",&x);
add(x);
}
ll ans=dfs(0,30);
printf("%lld\n",ans);*/
ll n;
scanf("%lld",&n);
for(ll i=1;i<n;i++)
{
ll u,v,w;
scanf("%lld %lld %lld",&u,&v,&w);
u++,v++;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
dfs0(1,-1);
for(ll i=1;i<=n;i++)
{
add(a[i]);
}
ll ans=dfs(0,30);
printf("%lld\n",ans);
}
/*
3
1 2 3
*/