2020牛客暑期多校训练营第五场Graph

G r a p h Graph

原题请看这里

题目描述:

W W 先生得到了一个具有 N N 个顶点和 N 1 N-1 条边的新图。 这是一个没有周期的连通图。 每个边缘都具有丑陋值。 为了使图形更美观, W W 先生希望您可以帮助他进行修改。 您可以一次删除或添加一个具有丑陋值的边,并且可以根据需要进行多次。 但是任何时候都应满足以下条件:
1. 1. 图形已连接。
2. 2. 对于图中的每个循环,该循环中所有丑陋值的 x o r xor 总和为 0 0
W先生想知道图中所有边的丑陋值的最小和。

输入描述:

第一行包含一个整数 N N ( ( 2 2 \leq N N \leq 100000 100000 ) ) N N ,接下来 N 1 N-1 行分别包含三个整数 U U V V W W ( ( 0 0 \leq U U V V < < N N 0 0 \leq W W < < 2 30 2^{30} ) ) 用丑陋的值 W W 表示顶点 U U V V 之间的边。

输出描述:

一个整数,图形中所有边的丑陋值的最小和。

样例输入:

6
0 1 1
1 2 4
1 3 3
0 4 5
0 5 2

样例输出:

7

思路:

我们令 e i e_i 为根节点到 i i 节点的所有边的异或和,由条件2可知:如果要从节点i和节点j之间连上一条边,则该边丑陋值为 e i e_i x o r xor e j e_j ,那么原题就可以转化为给定 N N 个节点,每个点有点权 e i e_i ,从节点i和节点j之间连上一条边的代价为 e i e_i x o r xor e j e_j ,求这 N N 个点的最小生成树。
最小生成树可以用 b o r u v k a boruvka 算法实现 最小生成树求法
题目给定的边的数量很多,所以我们可以用字典树来求所需边
Codeforces原题
Reach-top原题

A C AC C o d e Code

#include<bits/stdc++.h>
#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);
}

猜你喜欢

转载自blog.csdn.net/s260127ljy/article/details/107595052