[ABC218G] Game on Tree 2 树上游戏

news2024/9/25 3:20:00

[ABC218G] Game on Tree 2 树上游戏

文章目录

  • [ABC218G] Game on Tree 2 树上游戏
    • 题面翻译
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 样例 #2
      • 样例输入 #2
      • 样例输出 #2
    • 样例 #3
      • 样例输入 #3
      • 样例输出 #3
    • 题目大意
    • 分析
      • 水法
        • code
      • 正解
        • code

题面翻译

给定一棵树,以及树各节点的点权(点权为偶数)。起初有一个棋子在树的根结点(结点 1 1 1)处。

  • A A A B B B 两人轮流操作:将棋子移动到其所在节点的某个叶子节点。
  • 到某个节点的得分定义为:棋子经过所有结点点权的中位数。 K K K 个数的中位数定义如下:
    • K K K 为奇数时,中位数为 K K K 个数中第 K + 1 2 \frac{K+1}{2} 2K+1 小的值。
    • K K K 为偶数时,中位数为 K K K 个数中第 K 2 \frac{K}{2} 2K 小与第 K 2 + 1 \frac{K}{2}+1 2K+1 小的两数的平均值。
  • A A A 希望最后得分尽可能大, B B B 希望最后得分尽可能小。
  • 当棋子到达某个叶节点时,游戏结束。

A A A 先手操作, A A A B B B 都采取最优策略,求最终得分。

输入格式

入力は以下の形式で標準入力から与えられる。

$ N $ $ A_1 $ $ A_2 $ $ \ldots $ $ A_N $ $ u_1 $ $ v_1 $ $ u_2 $ $ v_2 $ $ \vdots $ $ u_{N-1} $ $ v_{N-1} $

输出格式

両者が最適に行動するとき、駒が訪れた頂点に書かれた数の(多重)集合の中央値を出力せよ。

样例 #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

题目大意

一棵树上有 n n n 个点,每个点有一个点值。在顶点1处有一块令牌,现在小T和小J开始玩游戏,它们轮流移动令牌到一个邻接点,令牌不能两次经过同一个点,最后令牌不能移动为止。令牌移动过程中经过的点,将它们的权值加入一个数组,求该数组的中位数。注意:小T移动时,他会采取最佳策略使得最终的中位数最大,而小J刚好相反,他会使得最终中位数最小。两个人都按照最佳策略去移动令牌。问最后的中位数是多少。

分析

水法

考试时用了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();
}

正解

观察一下我们可以发现,每个叶子节点代表一条路径,我们可以先用 D F S DFS DFS 统计出每个叶子结点的路径,并求出中位数,然后模拟。

好像会超时

我们发现可以用两个 multiset 或者对顶堆来维护这一条路径。

对顶堆 不会的可以看一下 这个

如果两个 m u l t i s e t multiset 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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/731784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode 106. 从中序与后序遍历序列构造二叉树

2023.7.8 让我很难受的一道题&#xff0c;个人感觉难度不止中等。 首先要知道的是知道了前序/后序 中序 之后&#xff0c;是可以构造出相应且唯一的二叉树的。 本道题的思路通过递归的方式根据中序遍历数组和后序遍历数组构建二叉树&#xff0c;并返回根节点。递归的结束条…

【通览一百个大模型】Anthropic LLM(Anthropic)

【通览一百个大模型】Anthropic LLM&#xff08;Anthropic&#xff09; 作者&#xff1a;王嘉宁&#xff0c;本文章内容为原创&#xff0c;仓库链接&#xff1a;https://github.com/wjn1996/LLMs-NLP-Algo 订阅专栏【大模型&NLP&算法】可获得博主多年积累的全部NLP、大…

Ubuntu安装VMtools实现与主机之间复制粘贴

目录 一、安装 VMware Tools 二、Ubuntu命令 一、安装 VMware Tools 右键点击你创建的系统&#xff0c;然后出现菜单下滑找到安装 VMware Tools&#xff08;T&#xff09; 这个点击安装&#xff1b; 右键点击你创建的系统&#xff0c;然后出现菜单下滑找到设置; 然后弹出虚…

USB转串口那些事儿—电源与防倒灌设计

USB转串口芯片和串口负载&#xff08;MCU、CPU、其他串口外设等&#xff09;的供电方式可以分为2个大类&#xff1a;统一供电和独立供电。 一、供电说明 统一供电是指USB芯片和串口负载使用同一电源&#xff0c;上下电同步&#xff0c;此时不会存在彼此之间电流倒灌的问题。 …

【异常错误】Unexpected option: --local_rank=0(pycharm可以run但是不可以debug)

今天在使用用run运行shell文件转为的cmd命令后&#xff0c;run可以正常运行&#xff0c;但是debug却出现问题&#xff0c;错误信息&#xff1a; Usage:pydevd.py --port N [(--client hostname) | --server] --file executable [file_options] Traceback (most recent call la…

复习C中文件操作

文章目录 Ⅰ. 重新谈论文件Ⅱ. C语言中的文件接口1、打开文件2、关闭文件3、读写函数4、文件的随机读写① fseek函数&#xff08;指定文件指针的位置&#xff09;② ftell函数&#xff08;求文件指针与起始位置的偏移量&#xff09;③ rewind&#xff08;让文件指针回到起始位置…

pdf转为ppt的超简单方法,就用这几个!

在我们的工作和生活中&#xff0c;PDF文件是不可或缺的文件格式之一。它以高准确性、整齐的页面排版和流畅的翻页而闻名&#xff0c;为我们处理文档提供了很大的帮助。然而&#xff0c;PDF文件的一个缺点是无法进行修改。当我们不小心输入错误数据或需要进行编辑时&#xff0c;…

python 常用数据结构-集合

Set集合 Set 集合集合定义集合使用&#xff1a;创建集合使用&#xff1a;成员检测集合方法集合方法 add()集合方法 update()集合方法 remove()集合方法 discard()集合方法 pop()集合方法 clear() 集合运算集合运算&#xff1a;交集集合运算&#xff1a;并集集合运算&#xff1a…

JAVA结课作品——超市管理系统

项目描述&#xff1a;一个简单的超市管理系统&#xff0c;能够实现用户登入和注册功能&#xff0c;共分为前台和后台两个主要界面&#xff0c;普通用户界面操作权限收到限制&#xff0c;只能对商品和销售记录进行简单查询操作&#xff0c;后台中可以进行商品的删除、修改、查询…

Java 设计模式——单例模式

目录 1.结构2.实现2.1.饿汉式2.1.1.静态变量2.1.2.静态代码块2.1.3.枚举方式 2.2.懒汉式2.2.1.synchronized 线程安全2.2.2.双重检查锁2.2.3.静态内部类方式 3.破坏单例模式3.1.序列化反序列化3.2.反射 4.问题解决5.JDK 源码解析——Runtime 类 1.结构 &#xff08;1&#xff…

03-MySQL-基础篇-SQL之DDL语句

SQL之DDL语句 前言DDL数据库操作表操作查询操作数据类型案例修改删除 前言 *本篇来学习下SQL中的DDL语句 DDL 全称Data Definition Language&#xff0c;数据定义语言&#xff0c;用来定义数据库对象(数据库&#xff0c;表&#xff0c;字段) 数据库操作 查询所有数据库 s…

数字与字符的对决:力扣“将所有数字用字符替换”的独特方法

本篇博客会讲解力扣“1844. 将所有数字用字符替换”的解题思路&#xff0c;这是题目链接。 本题的解题思路是&#xff1a;遍历字符串&#xff0c;按照题目描述修改字符。 有一个需要注意的点&#xff1a;循环的结束条件是什么呢&#xff1f;是s[i] ! \0’吗&#xff1f;不是的…

多线程(2):线程同步

线程同步是在多线程编程过程中对数据保护的一种机制&#xff0c;保护的数据是共享数据。共享数据就是多个线程共同访问的一块资源&#xff0c;也就是一块内存。假设有3个线程&#xff0c;其中A,B线程在同一个时间点往这块内存中写数据&#xff0c;于此同时C线程往这块内存中读数…

视频编码流程 YUV数据编码为H264数据

文章目录 1.视频编码流程2.实战demo3.相关编码知识点讲解1. 参数设置问题:2. 关于av_opt_set3. 关于码流设置 1.视频编码流程 2.实战demo #ifndef MAINBACK_C #define MAINBACK_C #endif // MAINBACK_C #include <stdint.h> #include <stdio.h> #include <stdl…

火车头采集器AI伪原创[php源码]

本文介绍php版本的火车头采集器AI伪原创&#xff0c;对于网站的原创内容&#xff0c;站长朋友们一定很头疼。作为一个草根站长&#xff0c;自己写原创文章太累了。当然&#xff0c;我并不是说你不能写。自己写原创文章是不现实的。时间是最大的问题。 也许有的站长朋友会问&…

自定义封装Mybatis的过程

手写持久层框架思路分析&#xff1a; 步骤1:加载数据库配置信息&#xff0c;包括数据库url&#xff0c;端口&#xff0c;数据库名字&#xff1b;加载所有sqlmapper文件。 步骤2: 创建javaBean&#xff0c;全局配置类&#xff0c;Configuration&#xff0c;映射配置类&#xff…

香橙派和树莓派基于官方外设开发

香橙派和树莓派基于官方外设开发 1.wiringPi外设SDK安装 方式一&#xff1a; git clone https://github.com/orangepi-xunlong/wiringOP //下载源码 cd wiringOP //进入文件夹 sudo ./build clean //清除编译信息 sudo ./build //编译方式二 通过windows浏览器打开https://…

全网最新网络安全学习路线

在各大平台搜的网安学习路线都太粗略了。。。。看不下去了&#xff01; 我把自己整理的系统学习路线&#xff0c;拿出来跟大家分享了&#xff01;点击查看详细路线图 建议的学习顺序&#xff1a; 一、网络安全学习普法&#xff08;心里有个数&#xff0c;要进去坐几年&#xf…

Java入门教程||Java 网络编程||Java 发送邮件

Java 网络编程 网络编程是指编写运行在多个设备&#xff08;计算机&#xff09;的程序&#xff0c;这些设备都通过网络连接起来。 java.net包中J2SE的API包含有类和接口&#xff0c;它们提供低层次的通信细节。你可以直接使用这些类和接口&#xff0c;来专注于解决问题&#…

基于simulink视频处理系统多核仿真(附源码)

一、前言 此示例演示如何使用 Simulink中的数据流执行域在多个内核上运行视频处理系统。 数据流执行域允许您在计算密集型系统的设计中使用多个内核。此示例演示数据流作为子系统的执行域如何提高模型的模拟性能。 二、视频中的对象计数 此示例演示如何使用基本形态运算符从…