原题请看这里
W W W先生得到了一个具有 N N N个顶点和 N − 1 N-1 N−1条边的新图。 这是一个没有周期的连通图。 每个边缘都具有丑陋值。 为了使图形更美观, W W W先生希望您可以帮助他进行修改。 您可以一次删除或添加一个具有丑陋值的边,并且可以根据需要进行多次。 但是任何时候都应满足以下条件:
1. 1. 1.图形已连接。
2. 2. 2.对于图中的每个循环,该循环中所有丑陋值的 x o r xor xor总和为 0 0 0。
W先生想知道图中所有边的丑陋值的最小和。
第一行包含一个整数 N N N ( ( ( 2 2 2 ≤ \leq ≤ N N N ≤ \leq ≤ 100000 100000 100000 ) ) ) N N N,接下来 N − 1 N-1 N−1行分别包含三个整数 U U U, V V V, W W W ( ( ( 0 0 0 ≤ \leq ≤ U U U, V V V < < < N N N, 0 0 0 ≤ \leq ≤ W W W < < < 2 30 2^{30} 230 ) ) ) 用丑陋的值 W W W表示顶点 U U U和 V V V之间的边。
一个整数,图形中所有边的丑陋值的最小和。
6
0 1 1
1 2 4
1 3 3
0 4 5
0 5 2
7
我们令 e i e_i ei为根节点到 i i i节点的所有边的异或和,由条件2可知:如果要从节点i和节点j之间连上一条边,则该边丑陋值为 e i e_i ei x o r xor xor e j e_j ej,那么原题就可以转化为给定 N N N个节点,每个点有点权 e i e_i ei,从节点i和节点j之间连上一条边的代价为 e i e_i ei x o r xor xor e j e_j ej,求这 N N N个点的最小生成树。
最小生成树可以用 b o r u v k a boruvka boruvka算法实现 最小生成树求法
题目给定的边的数量很多,所以我们可以用字典树来求所需边
Codeforces原题
Reach-top原题
#include
#define ll long long
using namespace std;
const int MAXN=6e6+5;
ll ans,n,u,v,w,s[MAXN][2],cnt,e[MAXN],h[MAXN],num=1,edgu[MAXN],dep[MAXN];
struct node
{
int v;
int nxt;
int w;
}a[MAXN];
void add(int x,int y,int z)
{
cnt++;
a[cnt].v=y;
a[cnt].w=z;
a[cnt].nxt=h[x];
h[x]=cnt;
}
void get(int x,int fa)
{
for(int i=h[x];i;i=a[i].nxt)
if(a[i].v!=fa)
{
e[a[i].v]=e[x]^a[i].w;
get(a[i].v,x);
}
}
ll find(int x,int y)
{
if(dep[x]==30) return e[edgu[x]]^e[edgu[y]];
ll ret=2e9;
bool flag=0;
for(int i=0;i<=1;i++)
if(s[x][i]&&s[y][i])
{
ret=min(ret,find(s[x][i],s[y][i]));
flag=1;
}
if(!flag)
{
if(s[x][0]&&s[y][1])
ret=min(ret,find(s[x][0],s[y][1]));
else if (s[x][1]&&s[y][0])
ret=min(ret,find(s[x][1],s[y][0]));
}
return ret;
}
void dfs(int x)
{
if(!x) return;
dfs(s[x][0]);
dfs(s[x][1]);
if(s[x][0]&&s[x][1])
ans+=find(s[x][0],s[x][1]);
}
int main()
{
edgu[1]=1;
scanf("%lld",&n);
for(int i=1;i<n;i++)
{
scanf("%lld%lld%lld",&u,&v,&w);
u++;
v++;
add(u,v,w);
add(v,u,w);
}
get(1,0);
for(int i=1;i<=n;i++)
{
int x=1;
for(int j=29;j>=0;j--)
{
int p=1<<j;
bool tmp=p&e[i];
if(!s[x][tmp])
{
s[x][tmp]=++num;
dep[num]=30-j;
edgu[num]=n+1;
}
x=s[x][tmp];
}
edgu[x]=i;
}
dfs(1);
printf("%lld\n",ans);
}