Codeforces1637F. Towers

传送门

题目大意

一棵 \(n(2\leq n\leq 2\times10^5)\) 个节点的树,每个节点 \(i\) 有一个权值 \(h_{i}(1\leq h_{i}\leq10^9)\) ,可以在节点上建立若干通信塔,建立效率为 \(e\) 的通信塔的花费为 \(e\) ,节点 \(x\) 可以接收到信号当存在一对节点 \(u,v(u\leq v)\) ,满足 \(min(e_{u},e_{v})\geq h_{x}\)\(x\)\(u\)\(v\) 的路径上,求使所有节点都能够接收到信号的最小花费。

思路

首先可以发现所有度数为 \(1\) 的节点上都需要建一个塔,不然其不会处在任何一对节点的路径上。之后我们以 \(h_{i}\) 最大的节点作为 \(root\) ,于是对于所有的非根节点 \(v\) ,其所在的子树中必须至少有一个效率 \(\geq h_{v}\) 的塔,因为总共有两个塔的效率最后需要 \(\geq h_{root}\) ,其中至少有一个不会在 \(v\) 为根的子树中,我们设 \(mx[v]\) 为以 \(v\) 为根的子树中效率最高的塔的效率,\(v\) 的度数为 \(1\)\(mx[v]\) 就等于 \(h_{v}\) ,在 \(dfs\) 时记录其所有儿子 \(to\)\(mx[to]\) 的最大值 \(mx1\) 和次大值 \(mx2\) ,之后如果 \(mx1<h_{v}\),那么就令 \(ans+=h_{v}-mx1\) ,最后 \(mx[v]=max(mx[v],mx1)\) 。对于根节点,因为 \(h_{root}\) 一定 \(>mx1\),于是 \(ans+=2h_{v}-mx1-mx2\) 即可。复杂度 \(O(n)\)

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
#define all(x) x.begin(),x.end()
//#define int LL
//#define lc p*2+1
//#define rc p*2+2
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 200010;

LL N, h[maxn], root = 0;
vector<int>G[maxn];
LL ans = 0, mx[maxn];
void add_edge(int from, int to)
{
	G[from].push_back(to);
	G[to].push_back(from);
}

void dfs(int v, int p)
{
	LL mx1 = 0, mx2 = 0;
	if (v != root && G[v].size() == 1)
	{
		mx[v] = h[v];
		ans += h[v];
		return;
	}
	for (int i = 0; i < G[v].size(); i++)
	{
		int to = G[v][i];
		if (to == p)
			continue;
		dfs(to, v);
		if (mx[to] >= mx1)
			mx2 = mx1, mx1 = mx[to];
		else
			mx2 = max(mx2, mx[to]);
	}
	if (v != root)
	{
		if (mx1 < h[v])
			ans += h[v] - mx1;
		mx[v] = max(mx1, h[v]);
	}
	else
		ans += h[v] * 2 - mx1 - mx2;
}

void solve()
{
	dfs(root, 0);
	cout << ans << endl;
}

int main()
{
	IOS;
	cin >> N;
	for (int i = 1; i <= N; i++)
	{
		cin >> h[i];
		if (h[i] > h[root])
			root = i;
	}
	int u, v;
	for (int i = 1; i < N; i++)
	{
		cin >> u >> v;
		add_edge(u, v);
	}
	solve();

	return 0;
}
posted @ 2022-03-17 15:47  Prgl  阅读(68)  评论(0)    收藏  举报