Accumulation Degree
解题思路
根据题目意思,结合图中信息,统计每个节点的度,记为dep数组,并建立一棵以1为根节点的树。
我们通过一次dfs(1,0)统计到以1为根节点,题目所求的最大积累度。
如果这个的子节点是叶子节点,那么
否则,
这个过程我们需要先找到最底层叶子节点向上推,所以 dfs的地方别写错了
后面我们考虑换根之后值的变化,如果这个节点 原先只有一棵子树,那么换根之后就变成叶子节点了所以他的子节点对应f数组直接为
否则,节点 存在多个子树,以其中一个子节点v,作为新的树根的话,w为两节点边权,对节点u来说,少了来自v的那一部分来源,对于v来说,多了一份来自u的来源,所以得到
注意着是从以1为根的子节点一步步向下推,需要得到父节点才可以算出子节点,dfs地方别写错了
时间复杂度 O(
)
Code
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;
inline int read() {
int s = 0, w = 1; char ch = getchar();
while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return s * w;
}
const int N = 2e5 + 7;
vector<pair<int, int> > tr[N];
int d[N], f[N], dep[N];
void dfs1(int u, int fa) {
for (int i = 0; i < tr[u].size(); ++i) {
int v = tr[u][i].first, w = tr[u][i].second;
if (v == fa) continue;
dfs1(v, u); //自底向上求得d数组
if (dep[v] == 1) d[u] += w;
else d[u] += min(w, d[v]);
}
}
void dfs2(int u, int fa) {
for (int i = 0; i < tr[u].size(); ++i) {
int v = tr[u][i].first, w = tr[u][i].second;
if (v == fa) continue;
if (dep[u] == 1) f[v] = d[v] + w;
else f[v] = d[v] + min(w, f[u] - min(w, d[v]));
dfs2(v, u); //自顶向下求得换根后的f数组
}
}
int main() {
int T = read();
while (T--) {
memset(dep, 0, sizeof(dep));
memset(d, 0, sizeof(d)); // +_+!!!一定要记得初始化吖
memset(f, 0, sizeof(f));
for (int i = 0; i < N; ++i) tr[i].clear();
int n = read();
for (int i = 1; i < n; ++i) {
int u = read(), v = read(), w = read();
tr[u].push_back(make_pair(v, w)); ++dep[u];
tr[v].push_back(make_pair(u, w)); ++dep[v];
}
dfs1(1, 0);
f[1] = d[1];
dfs2(1, 0);
printf("%d\n", *max_element(f + 1, f + 1 + n));
}
return 0;
}树学
解题思路
至于这道题,我当时比赛后补题是通过找重心的办法,其实也可以用上面换根的思想来实现,不过这题符合 的概念,直接找到重心,以重心为根dfs一遍就行了,不需要上方那样多次换根DP。
Code
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;
inline int read() {
int s = 0, w = 1; char ch = getchar();
while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return s * w;
}
const int maxn = 1e6 + 7;
vector<int> tree[maxn];
int n, minNode, minBalance;
//minNode当前重心节点
//minBalance当前重心节点的最大子树节点个数
int d[maxn], deep[maxn];
//d[i]表示以i为根的子树节点个数
void dfs1(int u, int fa) {
d[u] = 1; //节点本身
int maxSub = 0, size = tree[u].size(); //maxSub为节点u的最大子树节点个数
for (int i = 0; i < size; i++) {
int v = tree[u][i];
if (v != fa) {
dfs1(v, u);
d[u] += d[v];
maxSub = max(maxSub, d[v]);
}
}
maxSub = max(maxSub, n - d[u]);
if (maxSub < minBalance) {
minNode = u;
minBalance = maxSub;
}
}
void dfs2(int u, int fa) {
int size = tree[u].size();
for (int i = 0; i < size; ++i) {
int v = tree[u][i];
if (v == fa) continue;
deep[v] = deep[u] + 1;
dfs2(v, u);
}
}
int main() {
n = read();
for (int i = 1; i < n; i++) {
int u = read(), v = read();
tree[u].push_back(v);
tree[v].push_back(u);
}
minNode = 0; minBalance = 0x3f3f3f3f;
dfs1(1, 0);
dfs2(minNode, 0);
ll ans = 0;
for (int i = 1; i <= n; ++i) ans += deep[i];
printf("%lld\n", ans);
return 0;
}
京公网安备 11010502036488号