G.树上求和

G.树上求和

题意:
给你一棵n个顶点n-1条边的树,让你给n-1条边分别赋值1~n-1 ,每个数只能用一次,求整棵树最终任意两点之间的权值和。

题解:
我们只需要计算每条边被访问了多少次就行了,然后根据访问次数从小到大排序,最小的赋值最大的、…、最大的赋值最小的。

访问次数=该条边左边的端点数 * 该条边右边的端点数( size * (n-size) )

dfs找出每个顶点左边或者右边的个数,计算访问的次数,从小到大计算就ok了。

code:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<set>
#include<sstream>
using namespace std;
typedef long long ll;
const ll maxn=1e6+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
void io(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);}
ll he[maxn],ver[maxn],ne[maxn],vis[maxn];
ll size[maxn],ans[maxn];
ll cnt=0;
void add(ll x,ll y)
{
	ver[++cnt]=y;
	ne[cnt]=he[x];
	he[x]=cnt;	
} 
void dfs(ll u)
{
	size[u]=1;
	for(int i=he[u];i;i=ne[i])
	{
		ll num=ver[i];
		if(!vis[num])
		{
			vis[num]=1;
			dfs(num);
			size[u]+=size[num];
		}
	} 
}
int main()
{
	io();
	ll n;
	cin>>n;
	for(int i=1;i<n;i++)
	{
		ll x,y;
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	vis[1]=1;
	dfs(1);
	for(int i=2;i<=n;i++)
		ans[i]=size[i]*(n-size[i]);
	sort(ans+2,ans+n+1);
	ll sum=0;
	for(int i=2;i<=n;i++)	
		sum+=ans[i]*(n-i+1);
	cout<<sum<<endl;
	return 0;
}
发布了97 篇原创文章 · 获赞 30 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览