力扣312次周赛第四题,我还不会做,记录一下这类题型,代码来自y总。
给你一棵 n 个节点的树(连通无向无环的图),节点编号从 0 到 n - 1 且恰好有 n - 1 条边。
给你一个长度为 n 下标从 0 开始的整数数组 vals ,分别表示每个节点的值。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条 无向 边。
一条 好路径 需要满足以下条件:
开始节点和结束节点的值 相同 。
开始节点和结束节点中间的所有节点值都 小于等于 开始节点的值(也就是说开始节点的值应该是路径上所有节点的最大值)。
请你返回不同好路径的数目。
注意,一条路径和它反向的路径算作 同一 路径。比方说, 0 -> 1 与 1 -> 0 视为同一条路径。单个节点也视为一条合法路径。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-good-paths
将树中节点按节点权值排序,从小到大遍历,只能用左边权值比它小的点。
遍历后将他们加入树中,用并查集表示他们属于的集合,遍历每个集合。
- class Solution {
- public:
- vector<int> p;
-
- int find(int x) {
- if (p[x] != x) p[x] = find(p[x]);
- return p[x];
- }
-
- int numberOfGoodPaths(vector<int>& vals, vector
int >>& edges) { - int n = vals.size();
- vector
int>> g(n); -
- for (auto& e: edges) {
- int a = e[0], b = e[1];
- g[a].push_back(b);
- g[b].push_back(a);
- }
-
- vector<int> q(n);
- p.resize(n);
- for (int i = 0; i < n; i ++ ) p[i] = q[i] = i;
- sort(q.begin(), q.end(), [&](int a, int b) {
- return vals[a] < vals[b];
- });
-
- int res = 0;
- for (int i = 0; i < n; i ++ ) {
- int j = i + 1;
- while (j < n && vals[q[i]] == vals[q[j]]) j ++ ;
-
- for (int k = i; k < j; k ++ ) {
- int x = q[k];
- for (int y: g[x]) {
- if (vals[x] >= vals[y])
- p[find(x)] = find(y);
- }
- }
-
- unordered_map<int, int> hash;
- for (int k = i; k < j; k ++ )
- hash[find(q[k])] ++ ;
- for (auto& [k, v]: hash)
- res += v * (v + 1) / 2;
- i = j - 1;
- }
-
- return res;
- }
- };