[ABC218G] Game on Tree 2 树上游戏
[ABC218G] Game on Tree 2 树上游戏
目录
题面翻译
给定一棵树,以及树各节点的点权(点权为偶数)。起初有一个棋子在树的根结点(结点
与 两人轮流操作:将棋子移动到其所在节点的某个叶子节点。- 到某个节点的得分定义为:棋子经过所有结点点权的中位数。
个数的中位数定义如下:- 当
为奇数时,中位数为 个数中第 小的值。 - 当
为偶数时,中位数为 个数中第 小与第 小的两数的平均值。
- 当
希望最后得分尽可能大, 希望最后得分尽可能小。- 当棋子到达某个叶节点时,游戏结束。
若
输入格式
入力は以下の形式で標準入力から与えられる。
输出格式
両者が最適に行動するとき、駒が訪れた頂点に書かれた数の(多重)集合の中央値を出力せよ。
样例 #1
样例输入 #1
5
2 4 6 8 10
4 5
3 4
1 5
2 4
样例输出 #1
7
样例 #2
样例输入 #2
5
6 4 6 10 8
1 4
1 2
1 5
1 3
样例输出 #2
8
样例 #3
样例输入 #3
6
2 2 6 4 6 6
1 2
2 3
4 6
2 5
2 6
样例输出 #3
2
题目大意
一棵树上有
分析
水法
考试时用了5分钟打了一个贪心的做法,就是每次最优策略只考虑下一层的情况,居然拿到了67分的好成绩。
code
#include <bits/stdc++.h>
#define fu(x, y, z) for (int x = y; x <= z; x++)
using namespace std;
const int N = 1e5 + 5;
int n, cnt, hd[N], a[N], ans[N], sum, fa[N];
struct node {
int to, nt;
} e[N << 1];
void add(int u, int v) { e[++cnt].to = v, e[cnt].nt = hd[u], hd[u] = cnt; }
void dfs(int x, int y) {
int flg = 0, max1 = 0, min1 = 1e9 + 5, v, j, k;
for (int i = hd[x]; i; i = e[i].nt) {
v = e[i].to;
if (fa[x] == v)
continue;
flg = 1;
if (max1 < a[v])
max1 = a[v], j = v;
if (min1 > a[v])
min1 = a[v], k = v;
}
if (!flg)
return;
if (y) {
fa[j] = x;
ans[++sum] = a[j];
dfs(j, y ^ 1);
} else {
fa[k] = x;
ans[++sum] = a[k];
dfs(k, y ^ 1);
}
}
void solve() {
sort(ans + 1, ans + sum + 1);
if (sum % 2 == 1)
printf("%d", ans[sum / 2 + 1]);
else
printf("%d", ans[sum / 2] + ans[sum / 2 + 1] >> 1);
}
int main() {
scanf("%d", &n);
fu(i, 1, n) scanf("%d", &a[i]);
int u, v;
fu(i, 1, n - 1) {
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
ans[++sum] = a[1];
dfs(1, 1);
solve();
}
正解
观察一下我们可以发现,每个叶子节点代表一条路径,我们可以先用
好像会超时
我们发现可以用两个 multiset 或者对顶堆来维护这一条路径。
对顶堆 不会的可以看一下 这个
如果两个
否则就是第一个数列的最后一个数。
code
#include <bits/stdc++.h>
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
#define LL long long
using namespace std;
const int N = 1e5 + 5;
int n , cnt , hd[N] , a[N] , sum , fa[N] , max1[N] , min1[N] , ans1 , f[N] , ans[N];
struct node {
int to , nt;
} e[N << 1];
multiset<int> s1 , s2;
void add (int u , int v) { e[++cnt].to = v , e[cnt].nt = hd[u] , hd[u] = cnt; }
void dfs (int x , int fa) {
bool flg = 0;
if (x == 1) s1.insert(a[x]);
else {
auto t = s1.end();
t --;
if (a[x] <= *t) {
if (s1.size() == s2.size()) s1.insert(a[x]);
else {
s1.insert(a[x]);
auto y = s1.end();
y --;
s2.insert(*y) , s1.erase(y);
}
}
else {
if (s1.size() == s2.size()) {
s2.insert(a[x]);
auto y = s2.begin();
s1.insert(*y) , s2.erase(y);
}
else s2.insert(a[x]);
}
}
for (int i = hd[x] ; i ; i = e[i].nt) {
if (e[i].to == fa) continue;
flg = 1;
dfs (e[i].to , x);
}
if (!flg) {
int len = s1.size() + s2.size();
if (len & 1) {
auto t = s1.end();
t --;
f[x] = *t;
}
else {
auto a = s1.end();
a--;
auto b = s2.begin();
f[x] = *a + *b >> 1;
}
}
if (x != 1) {
auto t = s1.end ();
t --;
if (*t < a[x]) s2.erase(s2.lower_bound(a[x]));
else s1.erase(s1.lower_bound(a[x]));
if (s1.size() < s2.size()) {
auto y = s2.begin();
s1.insert(*y) , s2.erase(y);
}
if (s1.size() - s2.size() == 2) {
auto y = s1.end();
y --;
s2.insert(*y) , s1.erase(y);
}
}
}
void solve (int x , int fa , int flg) {
int res;
if (!flg) res = -1;
else res = 1e9 + 5;
int y , bl = 0;
for (int i = hd[x] ; i ; i = e[i].nt) {
y = e[i].to;
if (y == fa) continue;
bl = 1;
solve (y , x , flg ^ 1);
if (!flg) res = max (res , ans[y]);
else res = min (res , ans[y]);
}
if (bl) ans[x] = res;
else ans[x] = f[x];
}
int main () {
scanf ("%d" , &n);
fu (i , 1 , n) scanf ("%d" , &a[i]);
int u , v;
fu (i , 1 , n - 1) {
scanf ("%d%d" , &u , &v);
add (u , v) , add (v , u);
}
dfs (1 , 0);
solve (1 , 0 , 0);
printf ("%d" , ans[1]);
return 0;
}
如果人生会有很长,愿有你的荣耀永不散场
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端