Denso Create Programming Contest 2022(AtCoder Beginner Contest 239) E~F 题
E - Subtree K-th Max
-
题意:给定一个以
为根的树,节点个数为 ,每个点都有自己的点权。需要回答 次询问。每次询问给出两个数字 ,输出节点 的子树中第 大的值。保证询问中的子树节点个数大于 。 -
观察数据范围发现
最大为 20,所以 DFS 统计子树中前20大的值即可参考文章:浅谈 DFS 序
-
拓展:如果没有
的话就得考虑 DFS + 主席树来做了
PS: 子树问题可以用DFS转换成序列上的问题
AC Code
int n, q;
void solve() {
cin >> n >> q;
vector<vector<int>> X(n + 1, vector<int>(20));
for (int i = 1; i <= n; i += 1) cin >> X[i][0];
vector<vector<int>> G(n + 1);
for (int i = 1, a, b; i < n; i += 1) {
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
vector<int> tmp(40);
function<void(int, int)> DFS = [&](int u, int par) {
for (int v : G[u]) if (v != par) {
DFS(v, u);
merge(X[u].begin(), X[u].end(), X[v].begin(), X[v].end(), tmp.begin(), greater<int>());
for (int i = 0; i < 20; i += 1) X[u][i] = tmp[i];
}
};
DFS(1, 0);
for (int i = 0, V, K; i < q; i += 1) {
cin >> V >> K;
cout << X[V][K - 1] << "\n";
}
}
F - Construct Highway
- 题意:有
个点,你需要构造出一颗数,满足每个点的度数都为 ( 为题目给定的)。并目题目 已经给了 条边。
思路参考 (知乎—严格鸽)
考虑一下贪心,我们先找到一个度数剩余为1的点
但是怎么做呢?
我们可以按照题目给定的边来构造联通块,对于
以下度数为剩余的度数
所以我们需要维护联通块总的度数,并将联通块分为度数等于
可以得到,
这样的我们就可以构造出一颗树了,当然需要一些特判,具体我写到代码的注释里了。
int d[MAXN];
vector<int>g[MAXN];
int n, m, u, v;
void slove() {
cin >> n >> m;
int sum = 0;
for (int i = 1; i <= n; i++) { cin >> d[i]; sum += d[i]; }
if (sum != 2 * (n - 1))NO;//树的总度数为2*(n - 1)
UF uf = UF(n);
while (m--) {
cin >> u >> v;
d[u]--, d[v]--;
uf.Union(u, v);
if (d[u] < 0 || d[v] < 0)NO;//度数不能小于0
}
//处理联通块
for (int u = 1; u <= n; u++) {
while (d[u]--) {
//这里我们这样可以方便的搞出联通块的最后一个点
g[uf.findFather(u)].push_back(u);
}
}
//度数为1 度数为2
vector<int>c1; vector<vector<int>>c2;
for (int u = 1; u <= n; u++) {
if (g[u].size()) {
if (g[u].size() == 1)c1.push_back(g[u][0]);
else c2.push_back(g[u]);
}
}
vector<pair<int, int>>ans;
for (auto &vec : c2) {
int last = vec.back(); vec.pop_back();//剩下一个点
for (int u : vec) {
if (c1.size() == 0)NO;//如果c1没有了
int v = c1.back(); c1.pop_back();
ans.push_back({ u,v });
uf.Union(u, v);
}
c1.push_back(last);
}
//最后c1还是被push了,所以最后c1的个数一定要为2,如果个数大于2的话,不可能联通
if (c1.size() != 2)NO;
u = c1[0], v = c1[1];
ans.push_back({ u,v });
uf.Union(u, v);
if (uf.count == 1)
for (auto x : ans)cout << x.first << " " << x.second << endl;
else NO;
}
分类:
算法基础:搜索
, 刷题笔记: AtCoder
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 分享4款.NET开源、免费、实用的商城系统
· 解决跨域问题的这6种方案,真香!
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库
· 5. Nginx 负载均衡配置案例(附有详细截图说明++)