列表

详情


NC204440. 树上求和

描述

有一棵包含n个节点和n-1条边的树,规定树链(u,v)为树上从u到v的简单路径。
树的每条边上都有一个正整数,这个正整数被称作这条边的颜色,规定一条树链的权值w(u,v)为这条树链上所有边的颜色的代数和。
而整棵树的权值为所有不同的树链的权值的代数和。
已知所有边的颜色集合恰好为1到n-1这n-1个不同的正整数,请你为每条边安排一种颜色,使得这棵树的权值尽量小,你不需要给出具体方案,只需要求出这个最小的权值即可。

输入描述

测试数据第一行,是一个正整数,表示树的节点个数
接下来n-1行,每行两个用空格隔开的整数u,v,表示树上有一条边连接u和v

输出描述

一个整数,表示了这棵树的最小的权值。

示例1

输入:

4
1 2
2 3
3 4

输出:

19

说明:

w(1,2) + w(1,3) + w(1,4) + w(2,3) + w(2,4) + w(3,4) \\ = 3 + 4 + 6 + 1 + 3 + 2 \\ = 19

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 99ms, 内存消耗: 11008K, 提交时间: 2020-03-22 10:59:52

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll n,ans[N],cnt;
vector<int>g[N];
ll dfs(int u,int fa){
	ll sz=1;
	for(auto v:g[u])
		if(v!=fa) sz+=dfs(v,u);
	ans[cnt++]=sz*(n-sz);
	return sz;
}
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,0);
	sort(ans,ans+cnt);
	ll res=0;
	for(int i=n-1;i>0;i--)
		 res+=ans[n-i]*i;
		cout<<res<<endl;
	return 0;
} 

C++11(clang++ 3.9) 解法, 执行用时: 94ms, 内存消耗: 10988K, 提交时间: 2020-03-22 14:31:28

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll n,ans[N],cnt;
vector<int>g[N];
ll dfs(int u,int fa)
{
	ll sz=1;
	for(auto v:g[u])
	if(v!=fa) sz+=dfs(v,u);
	ans[cnt++]=sz*(n-sz);
	return sz;
}
int main()
{
	cin>>n;
	for(int i=1;i<n;i++)
	{
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,0);
	sort(ans,ans+cnt);
	ll res=0;
	for(int i=n-1;i>0;i--)
	res+=ans[n-i]*i;
	cout<<res<<endl;
	return 0;
}

上一题