长沙广告制作公司泉州seo技术
牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ
小红的陡峭值(四)
题目:
思路:
题目告诉我们关于树的陡峭值的定义,那一开始看起来无从下手,但是当我们选取某一个节点为根节点时,这个题目便看起来好做多了
我们这里选取节点1为根节点,那么接下来的每个节点的父节点都是唯一且确定的,我们这里可以定义一个arr[i],表示以i为根节点的陡峭值之和,其实这个有点像前缀和,但是是在树上的
那我们可以用一个dfs轻而易举的得到每个节点的陡峭值,那么接下来我们该如何分成两颗树呢?
显然,直接枚举删除那条边即可,那么我们再来考虑两树的差值如何计算呢,我们可以画出下图
假设我们要删除uv这条边,那么下树的值很好看出,不就是arr[v]吗,那上树呢?
显而易见,就是arr[1] - arr[v],同时注意一点,由于删除了uv,所以这条边的奉献也要删除,最终我们可以获得以下式子
上树:arr[v]
下树:arr[1] - arr[v] - abs(u-v)
二者一减就是答案了,同时要注意维护所有情况的最小值
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#define ll long long
using namespace std;int n;
vector<vector<int>> g(100005);
ll arr[100005];
ll ans = 9e18;
void dfs2(int father,int self)
{for (auto e : g[self]){if (e != father){dfs2(self, e);ll up = arr[1] - abs(e - self) - arr[e];ll down = arr[e];ans = min(ans, abs(up - down));}}
}
void dfs(int father, int self)
{for (auto e : g[self]){if (e != father){dfs(self, e);arr[self] += arr[e] + abs(self - e);}}
}void solve()
{cin >> n;for (int i = 0; i < n-1; i++){int u, v;cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs(0,1);dfs2(0, 1);cout << ans;
}int main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}