「Gym 102759I」Query On A Tree 17

news/2025/10/28 21:36:52/文章来源:https://www.cnblogs.com/keysky/p/19172784

题目大意

给定一颗 \(N\) 个节点以 \(1\) 为根的有根树,每次给以 \(u\) 为根的子树每点加 \(1\) 的值或给路径 \(u - v\) 上每点加 \(1\) 的值,每次修改后查询一个点 \(u\) 使得 \(\sum_{v = 1}^N dis(u, v)\) 最小。

题目转换

首先我们很贪心地想到点 \(u\) 是树的带权重心,证明如下:

假设点 \(u\) 是带权重心,\(sum_u\)\(u\) 的子树权值和,另取一点 \(v (v \neq u)\),令 \(u\) 为根,则对在路径 \(u - v\) 上每一点 \(p (p \neq u)\)

\[\sum_{i = 1}^N dis(i, p) - \sum_{i = 1}^N dis(i, fa_p) = N - 2sum_p \geq 0 \]

所以从 \(u\)\(v\) 的移动过程中每一步都不优,故 \(u\) 为我们的答案。

所以我们每次加子树,加路径,查带权重心。

然后再原树上带权重心 \(u\) 的子树权值和一定刚好严格大于整棵树权值和一半,否则一定不优,证明同上。换做 dfs 序,即一个区间权值和大于数列和一半。

做法详解

现在我们明确一下我们要求什么:找到一个深度最深的点 \(u\) 使得在 dfs 序下 \([dfn_u, dfn_u + siz_u - 1]\) 的权值和严格大于 \([1, n]\) 的权值和。

考虑怎么去找,我们先要猜个结论,设 \(pre_i\) 表示在 dfs 序下的权值前缀和,再找到一个 \(j\) 使得 \(pre_{j - 1}, pre_n - pre_j \leq \left \lfloor pre_n \right \rfloor\),则我们找到的点 \(u\) 一定满足 \(j \in [dfn_u, dfn_u + siz_u - 1]\) ,为什么呢?很简单,我们的 \([dfn_u, dfn_u + siz_u - 1]\) 权值和大于总权值一半,而无论是 \(pre_{j - 1}\) 还是 \(pre_n - pre_j\)\(j\) 的左右两边都小于总权值一半,所以我们的区间一定不会被包含于 \([1, j - 1]\)\([j + 1, n]\) ,故 \(rnk_j\) (dfs 序为 \(j\) 的结点) 一定在 \(u\) 的子树中。

\(rnk_j\) 很好找,然后我们因为要找深度最深的那个满足条件的点,且子树和满足单调性,所以满足条件的点一定是在树上连续的,故考虑倍增,每次check跳上去的点是否满足要求,若是,则跳,反之不跳,最后再跳 \(1\) 步(如果 \(rnk_j\) 满足条件就不管)得到答案 \(u\)

Solution

挺好实现的,思路清晰,大多都是模板,就是代码微长(也就百来行)。

/*
address:https://vjudge.net/problem/Gym-102759I
AC 2025/10/28 20:29
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
int dfn[N], siz[N], top[N], son[N], fa[N], dep[N], rnk[N];
int cntn;
vector<int>G[N];
int n, q;
struct SegmentTree {
#define ls (id << 1)
#define rs (id << 1 | 1)
#define mid (l + r >> 1)LL sum[N << 2], add[N << 2];inline void pushup(int id) { sum[id] = sum[ls] + sum[rs]; }inline void pushdown(int id, int l, int r) {if (add[id]) {add[ls] += add[id];add[rs] += add[id];sum[ls] += add[id] * (mid - l + 1);sum[rs] += add[id] * (r - mid);add[id] = 0;}}inline void modify(int id, int l, int r, int L, int R) {if (l >= L && R >= r) {sum[id] += r - l + 1;++add[id];return;}pushdown(id, l, r);if (L <= mid) modify(ls, l, mid, L, R);if (R > mid) modify(rs, mid + 1, r, L, R);pushup(id);}inline LL query(int id, int l, int r, int L, int R) {if (l >= L && R >= r) return sum[id];pushdown(id, l, r);LL ret = 0;if (L <= mid) ret += query(ls, l, mid, L, R);if (R > mid) ret += query(rs, mid + 1, r, L, R);return ret;}inline int search(int id, int l, int r, LL k) {if (l == r) return sum[id] <= k ? l : l - 1;pushdown(id, l, r);if (sum[ls] <= k) return search(rs, mid + 1, r, k - sum[ls]);else return search(ls, l, mid, k);}
}SGT;
const int K = 20;
int up[K][N];
inline void dfs1(int u) {dep[u] = dep[fa[u]] + 1;up[0][u] = fa[u];for (int i = 1;i < K;++i) up[i][u] = up[i - 1][up[i - 1][u]];siz[u] = 1;son[u] = 0;for (auto v : G[u])if (v != fa[u]) {fa[v] = u;dfs1(v);siz[u] += siz[v];if (siz[v] > siz[son[u]]) son[u] = v;}
}
inline void dfs2(int u) {dfn[u] = ++cntn;rnk[cntn] = u;if (!son[u]) return;top[son[u]] = top[u];dfs2(son[u]);for (auto v : G[u])if (v != son[u] && v != fa[u]) {top[v] = v;dfs2(v);}
}
LL sum;
inline void update(int u, int v) {while (top[u] != top[v]) {if (dep[top[u]] < dep[top[v]]) swap(u, v);SGT.modify(1, 1, n, dfn[top[u]], dfn[u]);sum += dfn[u] - dfn[top[u]] + 1;u = fa[top[u]];}if (dep[u] > dep[v]) swap(u, v);SGT.modify(1, 1, n, dfn[u], dfn[v]);sum += dfn[v] - dfn[u] + 1;
}
int main() {scanf("%d", &n);for (int i = 1;i < n;++i) {int u, v;scanf("%d%d", &u, &v);G[u].push_back(v);G[v].push_back(u);}dfs1(1);dfs2(1);scanf("%d", &q);while (q--) {int op, u;scanf("%d%d", &op, &u);if (op == 1) SGT.modify(1, 1, n, dfn[u], dfn[u] + siz[u] - 1), sum += siz[u];if (op == 2) {int v;scanf("%d", &v);update(u, v);}int p = SGT.search(1, 1, n, sum >> 1) + 1;u = rnk[p];for (int i = K - 1;i >= 0;--i)if (up[i][u] && SGT.query(1, 1, n, dfn[up[i][u]], dfn[up[i][u]] + siz[up[i][u]] - 1) <= sum >> 1) u = up[i][u];if (up[0][u] && SGT.query(1, 1, n, dfn[u], dfn[u] + siz[u] - 1) <= sum >> 1) u = up[0][u];printf("%d\n", u);}return 0;
}

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

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

相关文章

Mybatis使用简述

什么是 MyBatis? MyBatis 是一款优秀的 Java 持久层框架,它通过 XML 或注解的方式将 Java 对象与数据库中的记录进行映射。与传统的 JDBC 相比,MyBatis 极大地简化了数据库操作代码,让开发者能够更专注于业务逻辑而…

重组蛋白表达服务:CHO HEK293细胞系选择与表达优化方案

重组蛋白表达服务:CHO/HEK293细胞系选择与表达优化方案在生命科学研究领域,重组蛋白作为重要的科研试剂,其质量直接影响实验结果的可靠性。选择合适的表达系统并进行表达优化,是获得高质量重组蛋白的关键环节。本文…

C++里的代码命名规范

以下是 C++ 中最主流的几种命名规范: 1. 蛇形命名法 这是 C++ 标准库和许多 C++ 社区(如 Boost)最推荐的风格。小写蛇形命名法:所有字母小写,单词之间用下划线 _ 连接。适用于:变量、函数、命名空间、文件。 示例…

最小二乘问题详解6:梯度下降法

介绍了使用梯度下降法求解非线性最小二乘问题的原理与实现,通过C++和Eigen库对指数模型进行参数拟合,展示了算法流程、雅可比矩阵计算及收敛行为,并对比了其在机器学习与计算机视觉中的应用差异。1. 引言 在之前的两…

JavaWeb01

1.JavaWeb介绍 什么是JavaWeb?Web:全球广域网,也称万维网(www),能够通过浏览器访问的网站 JavaWeb:使用Java技术来解决相关web互联网领域的技术栈网页:展现数据 数据库:存储和管理数据 JavaWeb程序:逻辑处理数…

现代C++编程初体验

##实验任务1 ##代码#pragma once#include <string>// 类T: 声明 class T { // 对象属性、方法 public:T(int x = 0, int y = 0); // 普通构造函数T(const T &t); // 复制构造函数T(T &&t); …

Delphi 利用接口实现frame窗体间的通讯(互动)

需求说明: 程序设计:效果演示:设计思路: FrmCK 只负责发布事件,不关心谁在监听. FrmGrid 只负责响应事件,不关心事件来源. 创建过程: 一.创建接口单元FrmInterface. 全部代码如下:unit FrmInterface;interfaceusessy…

Python冒泡排序:简单易懂的算法实现

在编程的世界里,排序算法是数据处理的基础之一。冒泡排序(Bubble Sort)是一种简单且直观的排序算法,虽然它的效率不是最高的,但它非常适合初学者学习排序算法的基本概念。今天,我们就来详细探讨如何在Python中实…

SAM+ARM

一、首先是图像caption的生成。 输入的图像,被输入进BLIP的图像编码器得到图像嵌入,图像嵌入再经过(BLIP Image-grounded Text Decoder) 得到图像caption。ti表示caption的第i个单词,总共有L个单词。 但是,capti…

《代码大全2》观后感(二):需求分析——代码质量的“源头防线”

《代码大全2》观后感(二):需求分析——代码质量的“源头防线” “为什么明明按需求写的代码,最后还是要推翻重写?”这是我过去常有的困惑,直到读了《代码大全2》中“需求分析”的章节,才找到答案:很多时候,我…

NRF54LM20A 芯片的优点

多达 66 个 GPIO 7 个串行接口(SPI、TWI、UART、HS-SPI) 14 位 ADC、全局 RTC(在系统关闭状态下可用)、TDM、PDM、NFC、PWM、QDEC 等 显著降低的功耗 - 与 nRF52 系列相比,典型蓝牙低功耗应用场景下功耗降低约 30-50% …

零散点小总结(25.10.28)

今天练习了Dp,主要把Dp重新看待了一下,有以下几点Dp其实本质是一种表,用于储存子问题的答案 Dp中其实还有枚举,只是由于子问题被存入表中了,所以减少了时间复杂度 一个搜索其实就是Dp的暴力解,有很多的子问题,但…

Top Tree大学习

前言 \(Top Tree\) 用来解决 路径查询,动态 \(dp\) 等问题。 信息储存在 簇 中。 簇(\(Cluster\)) 树上一个边联通块,可以收缩成一条边,我们成这样的联通子图为 簇。 簇上的某些点与其它簇相接,我们称其为簇的 端…

乱学点东西目录

这里记录了各种各样的奇奇怪怪的算法/思路/数据结构,好玩! 乱学点东西#1 :二进制警报器可以自由转载

CFS任务的负载均衡(load balance)

前言 我们描述CFS任务负载均衡的系列文章一共三篇,第一篇是框架部分,第二篇描述了task placement和active upmigration两个典型的负载均衡场景。本文是第三篇,主要是分析各种负载均衡的触发和具体的均衡逻辑过程。 …

EVE-NG导入华为等镜像的方法

镜像下载Dynamips:思科设备真实IOS镜像,类似GNS3,电脑CPU利用率非常高。 IOL:IOU模拟器的镜像,基本完全支持思科设备二、三层功能。 QEMU:这已经不是镜像文件,而是KVM虚拟机安装操作系统后生成的磁盘文件,通常…

(简记)一类支配点对解决区间查询问题

前言:最近好像见了挺多这种题,记录一下。 支配点对 我们经常遇到树上或区间上关于 \(x,y\in[l,r]\) 一类的区间统计问题,且通常要求区间内点两两任意匹配并统计总贡献,这个贡献不具有简单可加性。我们往往通过找支…

2025 云斗

10/27 Contest 5 A:小分讨+dp C:发现是所有的数和它的倍数有限制,对于值域 \(n\) 这样的限制也只有 \(\sum\limits_{i=1}^n\frac{n}{i}=n\log n\) 个,考虑如何表示这些限制。 考虑对于限制 u,v,若两点都不是对方的…

c++ ranges随笔

ranges c++20引入,在<ranges>头文件中 建立在 std::algo 和 iterator基础上,并做了进一步的抽象集成 与之前相比更加的 安全、简洁、方便 // ranges concept template <typename T> concept range = req…

qoj14458. 调色滤镜

qoj14458. 调色滤镜 平面 \([1,10^9]\times[1,10^9]\) 上有 \(n\) 个点,点 \(i\) 位于 \((x,y)\),有颜色 \(c_i\in [0,9]\)。 有 \(q\) 次操作,每次对平面上一个矩形范围内的点的颜色作用映射 \(f:[0,9]\rightarrow…