尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

「Gym 102759I」Query On A Tree 17

「Gym 102759I」Query On A Tree 17
📅 发布时间:2026/6/19 8:07:08

题目大意

给定一颗 \(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;
}

相关新闻

  • Mybatis使用简述
  • 重组蛋白表达服务:CHO HEK293细胞系选择与表达优化方案
  • C++里的代码命名规范

最新新闻

  • LLM与RNN混合架构在代码理解中的应用与优化
  • 河北福亚斯保温建材口碑怎么样?深度评测与推荐 - mypinpai
  • 2026年好用的PTFE管道品牌,推荐哪家? - mypinpai
  • 邢台黄金回收门店实地探访全记录 - 余生黄金回收
  • 岳阳黄金回收实测六家正规门店靠谱吗 - 余生黄金回收
  • 零基础看懂 FPGA 实现 IIR 滤波器:大白话 + 手算实例 + 代码全拆解

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号