洛谷 P11378 [GESP202412 七级] 燃烧-普及/提高-
题目描述
小杨有一棵包含 nnn 个节点的树,其中节点的编号从 111 到 nnn。节点 iii 的权值为 aia_iai。
小杨可以选择一个初始节点引燃,每个燃烧的节点会将其相邻节点中权值严格小于自身权值的在节点间扩散直到不会有新的节点被引燃。
小杨想知道在合理选择初始节点的情况下,最多可以燃烧多少个节点。
输入格式
第一行包含一个正整数 nnn,表示节点数量。
第二行包含 nnn 个正整数 a1,a2,…,ana_1,a_2,\dots,a_na1,a2,…,an,代表节点权值。
之后 n−1n-1n−1 行,每行包含两个正整数 ui,viu_i,v_iui,vi,代表存在一条连接节点 uiu_iui 和 viv_ivi 的边。
输出格式
输出一个正整数,代表最多燃烧的节点个数。
输入输出样例 #1
输入 #1
5
6 2 3 4 5
1 2
2 3
2 5
1 4
输出 #1
3
说明/提示
子任务编号 | 数据点占比 | nnn |
---|---|---|
111 | 20%20\%20% | ≤10\leq 10≤10 |
222 | 20%20\%20% | ≤100\leq 100≤100 |
333 | 60%60\%60% | ≤105\leq 10^5≤105 |
对于全部数据,保证有 1≤n≤1051\leq n\leq 10^51≤n≤105,1≤ai≤1061\leq a_i\leq 10^61≤ai≤106。
solution
选择一个点作为根节点进行 dfs,记录所有子树的最多引燃节点数
再搜索一次,考虑到从父节点那一端可引燃的数量
代码
#include <iostream>
#include "bit"
#include "vector"
#include "unordered_set"
#include "set"
#include "queue"
#include "stack"
#include "algorithm"
#include "bitset"
#include "cstring"using namespace std;int n, a[100001], f[100001], x, y, Max;
vector<int> e[100001];/** 方法二:记忆化搜索,搜索不包含父节点的数量*/
int dfs(int u, int p) {int s = 1;for (int v: e[u]) {if (v != p) {if (a[v] < a[u]) {s += dfs(v, u);} else {dfs(v, u);}}}return f[u] = s;
}// 在搜索一次
void dfs2(int u, int p) {if (a[u] > a[p]) f[u] += f[p];for (int v: e[u]) {if (v != p) {dfs2(v, u);}}Max = max(Max, f[u]);
}int main() {cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];}for (int i = 1; i < n; i++) {cin >> x >> y;e[x].push_back(y);e[y].push_back(x);}dfs(1, 0);dfs2(1, 0);cout << Max;
}