力扣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
思路:
将树中节点按节点权值排序,从小到大遍历,只能用左边权值比它小的点。
遍历后将他们加入树中,用并查集表示他们属于的集合,遍历每个集合。
AC代码:
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<vector<int>>& edges) {
int n = vals.size();
vector<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;
}
};