Solution - 「OurOJ #47407」巧立名目
\(\mathscr{Description}\)
给定一棵含有 \(n\) 个点的带点权树和大小为 \(m\) 的有序点对集合 \(\{(s_i,t_i)\}_{i=1}^n\). 每次操作可以选择一个 \(s_i\), 将其更改为其一个邻接点. 求让所有 \(s_i=t_i\) 的过程中, \(\sum_{i=1}^m w(s_i)\) 的最大值的最小值.
\(m\le n\le5\times10^3\).
\(\mathscr{Solution}\)
首先需要明确: 并不一定沿着最短路将 \(s_i\) 移动到 \(t_i\), 我们可以通过将一个点卡在它能走到的一个点权较小的结点处用于腾挪.
"能走到的点权最小的结点"? 那就对点权建一个大根 Kruskal 重构树叭. 每个结点能走到的点权最小的结点就是其子树最小值.
如何进行移动呢? 不妨记一开始的位置集合为 \(S_0\), 我们肯定先将每个点都移动向各自子树内点权最小的结点, 得到 \(S_0'\); 接下来再选择 \(S_0'\) 中的某个点 \(x\) 走到其在 \(S_0\) 中对应结点的父亲, 得到 \(S_1\). 设点 \(u\) 在 Kruskal 重构树上的子数最小值为 \(l(u)\), 那么在这一过程中, 点权和将在 \(\sum_{u\in S_1}w(u)\) 达到峰值, 这一值也就是 \(\sum_{u\in S_0}l(u)-l(x)+w(p_x)\).
当然, 这仅仅是移动的一般情况. 当务之急是确定如何选取这个 \(x\in S_0\). 不妨记目前答案为 \(\textit{ans}\), 那么我们有一个暴力做法: 不断令 \(\textit{ans}\gets\textit{ans}+1\) 直到恰好出现一个可以移动的 \(x\), 由于 \(x\) 上移不会让子树最小值变大, 因此此时移动 \(x\) 肯定是不劣. 我们只需要求出这个时候的 \(\textit{ans}\) 及其对应的 \(x\) 就能完成迭代了. 很显然, 此时 \(\textit{ans}\ge\sum_{u\in S_0}l(u)+\min\{\Delta_x\}\) (可能 \(\Delta_x<0\)), 所以直接取 \(\arg\min\{\Delta_x\}\) 就是最有的决策.
现在, 我们完成了 "从 \(S\) 向上爬" 的策略, 不过这并不能指导我们如何走到 \(T\). 这里有一个思维 trick: 因为移动过程是可逆的, 所以我们不妨让 \(T\) 向上爬. 当目前的 \(\textit{ans}\) 合法时, 有一个必要条件: \(S\) 能爬到的最高点对应 \(T\) 能爬到的最高点.
问题是, 在我们的策略中, 当一个 \(s_i\) 爬到最高点, 其余所有 \(s\) 都是呆在某个子树最小值位置的, 如何拼接从 \(S\) 出发的方案和从 \(T\) 出发的方案呢? 其实很简单, 当 \(S\) 能爬到的最高点对应 \(T\) 能爬到的最高点时, 我们先让所有 \(S\) 走到自己最高点所对应的子树最小值位置 --- 挨个移动, 一定可行. 此后, 将这些最小值位置调整到各自在 \(T\) 中的最小值位置 --- 这些最小值一一相等, 完全不会影响方案可行性. 最后, 我们已经完全移动把结点丢到 \(T\) 的方案内了, 回溯到重点即可.
直接用堆模拟贪心过程, 可以做到 \(\mathcal O(nm\log m)\).
\(\mathscr{Code}\)
/*+Rainybunny+*/
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
typedef long long LL;
typedef std::pair<int, int> PII;
#define fi first
#define se second
const int MAXN = 5e3;
int n, m, val[MAXN + 5], ord[MAXN + 5];
std::vector<int> G[MAXN + 5], T[MAXN + 5];
struct DSU {
int fa[MAXN + 5];
inline void init() {
rep (i, 1, n) fa[i] = i;
}
inline int find(const int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
} dsu;
int fa[MAXN + 5], mn[MAXN + 5], cur[MAXN + 5][2];
inline void init(const int u) {
mn[u] = val[u];
for (int v: T[u]) fa[v] = u, init(v), mn[u] = std::min(mn[u], mn[v]);
}
int main() {
scanf("%d", &n);
rep (i, 1, n) scanf("%d", &val[i]);
rep (i, 2, n) {
int u, v; scanf("%d %d", &u, &v);
G[u].push_back(v), G[v].push_back(u);
}
std::iota(ord + 1, ord + n + 1, 1);
std::sort(ord + 1, ord + n + 1,
[](const int u, const int v) {
return val[u] < val[v];
}
);
dsu.init();
rep (i, 1, n) {
int u = ord[i];
for (int v: G[u]) if (val[v] < val[u] + (v < u)) {
// printf("%d %d\n", u, dsu.find(v));
T[u].push_back(dsu.find(v)), dsu.fa[dsu.find(v)] = u;
}
}
init(ord[n]);
scanf("%d", &m);
int rest = 0;
LL s0 = 0, t0 = 0, sum[2] = {};
std::priority_queue<PII, std::vector<PII>, std::greater<PII>> heap;
rep (i, 1, m) {
int s, t;
scanf("%d %d", &s, &t);
cur[i][0] = s, cur[i][1] = t;
rest += s != t, s0 += val[s], t0 += val[t];
sum[0] += mn[s], sum[1] += mn[t];
// printf("%d %d %d\n", s, t, tar[i]);
if (fa[s]) heap.emplace(val[fa[s]] - mn[s], i);
if (fa[t]) heap.emplace(val[fa[t]] - mn[t], -i);
}
LL ans = std::max(s0, t0);
while (rest) {
PII p = heap.top(); heap.pop();
int tp = p.se < 0, id = tp ? -p.se : p.se;
ans = std::max(ans, sum[tp] + p.fi);
rest += cur[id][0] == cur[id][1], sum[tp] -= mn[cur[id][tp]];
cur[id][tp] = fa[cur[id][tp]];
rest -= cur[id][0] == cur[id][1], sum[tp] += mn[cur[id][tp]];
if (fa[cur[id][tp]]) {
heap.emplace(val[fa[cur[id][tp]]] - mn[cur[id][tp]], p.se);
}
}
printf("%lld\n", ans);
return 0;
}
Solution - 「OurOJ #47407」巧立名目的更多相关文章
- Solution -「OurOJ 46544」漏斗计算
\(\mathcal{Description}\) Link. 定义一个运算结点 \(u\) 有两个属性:当前容量 \(x_u\).最大容量 \(V_u\).提供以下单元操作: I 读入一个整 ...
- Solution -「ARC 104E」Random LIS
\(\mathcal{Description}\) Link. 给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...
- Solution -「CTS 2019」「洛谷 P5404」氪金手游
\(\mathcal{Description}\) Link. 有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...
- Solution -「BZOJ 3812」主旋律
\(\mathcal{Description}\) Link. 给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...
- Solution -「CF 1342E」Placing Rooks
\(\mathcal{Description}\) Link. 在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...
- Solution -「FJWC 2020」人生
\(\mathcal{Description}\) OurOJ. 有 \(n\) 个结点,一些结点有染有黑色或白色,其余待染色.将 \(n\) 个结点染上颜色并连接有向边,求有多少个不同(结点 ...
- Solution -「简单 DP」zxy 讲课记实
魔法题位面级乱杀. 「JOISC 2020 Day4」治疗计划 因为是不太聪明的 Joker,我就从头开始理思路了.中途也会说一些和 DP 算法本身有关的杂谈,给自己的冗长题解找借口. 首先,治疗方案 ...
- Solution -「基环树」做题记录
写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...
- Solution -「WC 2022」秃子酋长
\(\mathscr{Description}\) Link. (It's empty temporarily.) 给定排列 \(\{a_n\}\),\(q\) 次询问,每次给出 \([l,r ...
- Solution -「JSOI 2019」「洛谷 P5334」节日庆典
\(\mathscr{Description}\) Link. 给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的). \(|S|\le3\time ...
随机推荐
- linux环境安装pip
1.下载pip安装包 https://files.pythonhosted.org/packages/ce/ea/9b445176a65ae4ba22dce1d93e4b5fe182f953df71a ...
- Linux基础-学会使用命令帮助
概述 使用 whatis 使用 man 查看命令程序路径 which 总结 参考资料 概述 Linux 命令及其参数繁多,大多数人都是无法记住全部功能和具体参数意思的.在 linux 终端,面对命令不 ...
- Windows 多次制作母盘,备份文件变大的问题
公司产品基于Win11 23H2镜像版本制作母盘,我们发现随着版本迭代,基于上一版本母盘生成新母盘备份,母盘文件会越来越大. 此处说明下镜像与母盘文件的区别, 1. 镜像是指操作系统的压缩文件,常见格 ...
- three.js+vue智慧社区web3d数字孪生三维地图
案例效果截图如下: 具体案例场景和功能,详见b站视频: https://www.bilibili.com/video/BV1Bb421E7WL/?vd_source=7d4ec9c9275b9c7d1 ...
- switch、case语句的问题
switch.case语句: 点击查看代码 int state = 1; switch(state) { case 1: { //状态1执行的程序 } case 2: { //状态2执行的程序 } d ...
- 程序员如何借势AI提高自己:从高效工作到技能升级的全面指南
又是一年1024,时光荏苒,转眼又到了这个特别的日子.坦白说,这篇文章我其实并不太想写,因为我并没有通过AI找到普适于程序员群体的高效赚钱秘籍.然而,反思过去的工作,我发现利用AI的确让我在工作中变得 ...
- 6.Kubernetes集群管理工具kubectl
Kubernetes集群管理工具kubectl 概述 kubectl是Kubernetes集群的命令行工具,通过kubectl能够对集群本身进行管理,并能够在集群上进行容器化应用的安装和部署 命令格式 ...
- GPU 环境搭建指南:使用 GPU Operator 加速 Kubernetes GPU 环境搭建
本文主要分享如何使用 GPU Operator 快速搭建 Kubernetes GPU 环境. 1. 概述 上一篇文章 GPU 使用指南:如何在裸机.Docker.K8s 等环境中使用 GPU 分享了 ...
- cmu15545笔记-查询优化(Query Optimization)
目录 概述 Heuristics / Rules Cost-based Search Single relation Mutiple relation Genertive / Bottom-Up Tr ...
- javaScript 的面向对象程序
理解对象 属性类型 数据属性(数据属性包含一个数据值的位置,这个位置可以读取和写入值,数据属性有4描述) [Configurable]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属 ...