[NOI2011] 道路修建

洛谷链接:https://www.luogu.com.cn/problem/P2052

我们先思考一下怎么表达题意

 

题目要求的是求出当前点和其他点连线之间的特殊权值之和

这种特殊权值就是左边点的集合和右边点的集合差的绝对值*边的权值(abs(size[u]-size[v])*w[i])

这种很容易让人想到统计每个节点下面的子树

也确实需要统计每个节点下面的子树

但是我们知道刚开始我们是任意选一个点去遍历的,也就是说指不定哪个点作为根节点,那么我们就需要想如何通过一次两次的dfs来得到我们想要的答案

因为n^2的做法是行不通的

我们来实践一下看思维难度主要在哪里:

我们先选一个不那么特殊的点,2点

2点刚开始的size肯定是1,那么在遍历到周边5点的时候肯定要满足一种情况:

也就是5作为一个孤立的点和2点连接,那么2点在和5点连接时的size实际上是n!

这时候我们就要考虑了,是刚开始就预处理好每个点下面的子树的大小吗?

我们可以沿着这个思路往下想,看能不能保证任意一个点作为根节点得到的结果都是一样的

当我们把2点作为根节点,遍历到5点和遍历到1点的时候,情况都是可控的

但是1点往下呢?

你会发现1点下面有3个分叉!

也就是说当1点往下遍历的时候若是遍历到4点,那么size[4] = 1,显然4点的处境和5点是一样的,这时候size[1]反而是n

这样可行吗?

我们应该换思路了

也就是说每个点和周围点连接的size之差其实是和它的父节点没什么关系的!只和它自己本身的子树大小有关系啊!

这同时也启示我们:即使是要表达子节点size大小和父节点size大小,也不用一定就要扯上关系

那么,我们要不要维护size这个数组要维护?

当然你要维护,而且是一边维护一边统计值并累加

为什么就不能先统计,之后再累加呢?

也可以,不过就是两次dfs罢了

这个题的思想就是让我们求出每个点的子树,仅此而已

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N  = 2e6+10;         //ll和两倍点和数据范围需要特别注意!!! 
ll e[N],ne[N],h[N],w[N],size[N],idx;
ll n;
ll value;
void add(int a,int b,int c)
{
	e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
}
void dfs(int u,int fa)
{
	size[u] = 1;
	for(int i=h[u];~i;i=ne[i])
	{
		int j = e[i];
		if(j==fa) continue;
		dfs(j,u);
		size[u] += size[j];
		value += (ll)(w[i]*abs(2*size[j]-n)); 
	}
} 
/*void cal(int u,int fa)
{
	for(int i=h[u];~i;i=ne[i])
	{
		int j = e[i];
		if(j==fa) continue;
		dfs(j,u);
		value += (ll)(w[i]*abs(2*size[j]-n));
	}
}*/
int main()
{
	memset(h,-1,sizeof h);
	cin>>n;
	for(int i=1;i<=n-1;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c),add(b,a,c);
	}
	dfs(1,0);
	//cal(1,0);
	cout<<value;
	return 0;
}

要加油啊!!!

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值