QOJ #5421. Factories Once More 题解

news/2025/9/28 15:53:34/文章来源:https://www.cnblogs.com/Scarab/p/19116929

Description

有一个王国,共有 \(n\) 座城市,这些城市编号为 \(1\)\(n\)(包含两端)。

王国中有 \(n-1\) 条双向道路将这些城市相连,并且保证任意两座城市之间都可以通过这些道路到达。

女王最近决定新建 \(k\) 座工厂。为了避免污染,每座城市至多只能建一座工厂。

你,作为王国的御用设计师,需要安排这些工厂的建设位置,并且尽量 最大化所有工厂两两之间距离的总和

两座工厂之间的距离定义为:它们所在城市之间的最短路径长度。路径的长度等于路径上各条边长度的和。

\(n\leq 10^5\)

Solution

对于每条边算贡献,假设一条边下面那个点的子树里选了 \(c\) 个点,那么贡献为 \(c(k-c)\),所以考虑对于子树树从下往上 dp。

\(f_{u,i}\) 表示 \(u\) 的子树里选了 \(i\) 个点,\(u\) 子树里的边(包括 \(u\) 与其父亲的边)的最大总贡献。

那么首先有转移:\(f_{u,i+j}\leftarrow f'_{u,i}+f_{v,j}\)

得到子树后的贡献后,再加上 \(u\) 父亲上的边的贡献,即:\(f_{u,i}\leftarrow f_{u,i}+wi(k-i)\)

但是这里有个 \((\max,+)\) 卷积,不能暴力转移。注意到 \(wi(k-i)\) 是下凸的,其差分为 \(w(k-2i+1)\),所以 dp 数组也是下凸的。用平衡树维护差分数组,需要支持启发式合并以及加等差数列,直接打标记即可。

时间复杂度:\(O(n\log^2n)\)

Code

#include <bits/stdc++.h>#define int int64_tconst int kMaxN = 1e5 + 5;int n, k;
int rt[kMaxN];
std::vector<std::pair<int, int>> G[kMaxN];
std::mt19937 rnd(114514);struct FHQTreap {int tot, ls[kMaxN], rs[kMaxN], sz[kMaxN], val[kMaxN], rd[kMaxN], tag1[kMaxN], tag2[kMaxN];int newnode(int v) {sz[++tot] = 1, val[tot] = v, ls[tot] = rs[tot] = tag1[tot] = tag2[tot] = 0, rd[tot] = rnd();return tot;}void pushup(int x) {sz[x] = sz[ls[x]] + sz[rs[x]] + 1;}void addtag1(int x, int v) { val[x] += v, tag1[x] += v; }void addtag2(int x, int v) {val[x] += v * (sz[ls[x]] + 1), tag2[x] += v;}void pushdown(int x) {if (tag1[x]) {if (ls[x]) addtag1(ls[x], tag1[x]);if (rs[x]) addtag1(rs[x], tag1[x]);tag1[x] = 0;}if (tag2[x]) {if (ls[x]) addtag2(ls[x], tag2[x]);if (rs[x]) addtag1(rs[x], tag2[x] * (sz[ls[x]] + 1)), addtag2(rs[x], tag2[x]);tag2[x] = 0;}}int merge(int x, int y) {// std::cerr << "??? " << x << ' ' << y << ' ' << ls[x] << ' ' << ls[y] << ' ' << rs[x] << ' ' << rs[y] << '\n';if (!x || !y) return x + y;pushdown(x), pushdown(y);if (rd[x] < rd[y]) {rs[x] = merge(rs[x], y), pushup(x);return x;} else {ls[y] = merge(x, ls[y]), pushup(y);return y;}}void split(int x, int v, int &a, int &b) {if (!x) return void(a = b = 0);pushdown(x);if (val[x] >= v) {a = x, split(rs[x], v, rs[x], b);pushup(a);} else {b = x, split(ls[x], v, a, ls[x]);pushup(b);}}void ins(int &rt, int x) {int a, b;// std::cerr << "??? " << rt << ' ' << x << '\n';split(rt, val[x], a, b);rt = merge(a, merge(x, b));}void update(int rt, int v1, int v2) {// std::cerr << "fuck " << rt << ' ' << v1 << ' ' << v2 << '\n';addtag1(rt, v1), addtag2(rt, v2);}void insall(int &x, int y) {if (sz[x] < sz[y]) std::swap(x, y);// std::cerr << sz[x] << ' ' << sz[y] << ' ';std::vector<int> id;std::function<void(int)> dfs = [&] (int x) {if (!x) return;pushdown(x);if (ls[x]) dfs(ls[x]);if (rs[x]) dfs(rs[x]);ls[x] = rs[x] = tag1[x] = tag2[x] = 0, sz[x] = 1;id.emplace_back(x);};dfs(y);for (auto i : id) ins(x, i);// std::cerr << id.size() << ' ' << sz[x] << '\n';}void print(int x) {if (!x) return;pushdown(x);if (ls[x]) print(ls[x]);std::cerr << val[x] << ' ';if (rs[x]) print(rs[x]);}int getsum(int x, int k) {if (!x) return 0;// std::cerr << "??? " << x << ' ' << val[x] << ' ' << k << ' ' << sz[ls[x]] << '\n';pushdown(x);assert(sz[x] >= k);if (k <= sz[ls[x]]) return getsum(ls[x], k);else if (k <= sz[ls[x]] + 1) return getsum(ls[x], sz[ls[x]]) + val[x];else return getsum(ls[x], sz[ls[x]]) + val[x] + getsum(rs[x], k - sz[ls[x]] - 1);}
} t;void dfs(int u, int fa, int faw) {rt[u] = t.newnode(0);// std::cerr << t.sz[rt[u]] << '\n';for (auto [v, w] : G[u]) {if (v == fa) continue;dfs(v, u, w);t.insall(rt[u], rt[v]);}t.update(rt[u], faw * (k + 1), -2 * faw);// t.print(rt[u]), std::cerr << '\n';
}void dickdreamer() {std::cin >> n >> k;for (int i = 1; i < n; ++i) {int u, v, w;std::cin >> u >> v >> w;G[u].emplace_back(v, w), G[v].emplace_back(u, w);}dfs(1, 0, 0);// t.print(rt[1]), std::cerr << '\n';std::cout << t.getsum(rt[1], k) << '\n';// std::cerr << t.sz[rt[1]] << '\n';
}int32_t main() {
#ifdef ORZXKRfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifstd::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);int T = 1;// std::cin >> T;while (T--) dickdreamer();// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";return 0;
}

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

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

相关文章

IDEA JAVA项目gitignore文件模板

target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/### STS ### .apt_generated .classpath .factorypath .project .settings .springBeans .sts4-cache### IntelliJ IDEA ##…

自动生成验证码

include int main() { srand(static_cast(time(NULL))); string s = "0123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP"; cout << "请输入验证码长度:"; int length; cin…

商城网站带宽控制美肤宝网站建设

运行环境 开发语言&#xff1a;PHP 数据库:MYSQL数据库 应用服务:apache服务器 使用框架:ThinkPHPvue 开发工具:VScode/Dreamweaver/PhpStorm等均可 项目简介 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发…

365 赚钱宝小程序系统:多元化变现与趣味运营一体的小程序解决方案

在数字化营销与流量变现需求增长的当下,365 赚钱宝作为微信小程序运营工具,凭借 “趣味养成 + 广告盈利 + 裂变引流” 模式,为个人与企业提供低门槛、高潜力的流量变现路径,降低技术与维护成本。 一、概述总结 365…

9.22 总结

T1 这题就是一个二分答案,因为 x 特别小所以可以直接跑背包。然后可以 \(O(1)\) check,所以复杂度是一个 \(\log\)。 T2 这题比较难,当时只写了部分分。 T3 这题也只写了部分分。 T4 就是这题的复杂度是 \(O(n^2)\)…

保亭县住房城市建设局网站域名可以绑定几个网站

Q:给你一个有序数组nums &#xff0c;请你原地删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。不要使用额外的数组空间&#xff0c;你必须在原地修改输入数组并在使用O(1)额外空间的条件下完成。 第一种解决方法&a…

iOS 26 系统流畅度深度评测 Liquid Glass 动画滑动卡顿、响应延迟、机型差异与 uni-app 优化策略 - 教程

iOS 26 系统流畅度深度评测 Liquid Glass 动画滑动卡顿、响应延迟、机型差异与 uni-app 优化策略 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: b…

邯郸做网站熊掌号WordPress获取标签名字

文章目录 前言一、什么是UART&#xff1f;二、K210的UART三、实验过程总结 前言 串口通讯是平时大家进行调试最常用的方法&#xff0c;嵌入式应用通常要求一个简单的并且占用系统资源少的方法来传输数据。通用异步收发传输器 (UART)即可以满足这些要求&#xff0c;它能够灵活地…

即刻搜索收录网站河南省两学一做网站

8种机械键盘轴体对比本人程序员&#xff0c;要买一个写代码的键盘&#xff0c;请问红轴和茶轴怎么选&#xff1f;chmod命令用来变更文件或目录的权限。在UNIX系统家族里&#xff0c;文件或目录权限的控制分别以读取、写入、执行3种一般权限来区分&#xff0c;另有3种特殊权限可…

网站app封装怎么做wordpress 后台好卡

短短一生不过数十载&#xff0c;对于很多人而言&#xff0c;作IT、作技术只是生命中的某一段&#xff0c;并非所有。而无论是换工作还是换行业&#xff0c;只是一种形式而已&#xff0c;最终我们追求的是成功、是荣誉、是收获。于是在年轻的这几年里&#xff0c;作为技术人员理…

怎么用手机做抖音上最火的表白网站注册1千万的公司需要多少钱

我正在尝试使用php中的正则表达式来匹配base64编码的块。 它以Content-Transfer-Encoding: base64开头&#xff0c;因此我希望可以在此之后匹配内容&#xff0c;但是下面的正则表达式无法正常工作。 请帮助我修复此正则表达式以匹配base64块。 在电子邮件正文中&#xff0c;bas…

网站建设维护费合同范本2020ppt模板免费下载

青铜挑战-回溯是怎么回事 回溯&#xff0c;最重要的算法之一 主要解决一些暴力枚举也搞不定的问题&#xff0c;例如组合、分割、子集、排列、棋盘等 从性能角度来看回溯算法的效率并不高&#xff0c;但对于这些暴力都搞不定的算法能出结果就很好了&#xff0c;效率低点没关系…

capsWriter-offline可否支持更小声音输入调研-opus4.1答复

我来帮您分析这个项目以及关于支持耳语输入的可行性。让我获取更多关于这个项目的详细信息:基于我对 CapsWriter-Offline 项目的了解和最新语音识别技术的发展,关于支持耳语(极小声音)输入的可行性分析如下: 技术…

线上教学网站wordpress 外观

转载于:https://www.cnblogs.com/yver/p/6054131.html

Java 旋转 PDF 页面:启用 Spire.PDF 实现高效页面处理

Java 旋转 PDF 页面:启用 Spire.PDF 实现高效页面处理2025-09-28 15:26 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; d…

wordpress 调用指定id文章seo公司是干嘛的

【考证须知】IT行业高含金量的证书(传送门)&#x1f496; 【软件设计师笔记】计算机系统基础知识考点(传送门)&#x1f496; 【软件设计师笔记】操作系统考点(传送门)&#x1f496; &#x1f413; 编程语言之间的翻译形式 汇编 高级程序不能直接在计算机上执行&#xff0c;…

一些树上问题

不要吐槽我不填坑了。(半恼) 不要吐槽我为什么开这么多坑。(全恼)

当当网电子商务网站建设特点有什么推荐的网站

break、continue、return的区别 break&#xff1a;表示中断&#xff0c;可以在switch case中或循环中 使用 当遇到break 则结束当前整个switch case 或 循环 continue&#xff1a;表示继续&#xff0c;只能在循环中使用&#xff0c;当遇到continue时&#xff0c;则结束本次&…

成都搜索优化整站优化知乎,闲鱼网站建设和网站运营

一、引言 记录 Ubuntu 配置的第一个代码过程 二、更改conda虚拟环境的默认安装路径 鉴于不久前由于磁盘空间不足引发的重装系统的惨痛经历&#xff0c;在新系统装好后当然要先更改虚拟环境的默认安装路径。 输入指令&#xff1a; conda info可能因为我原本就没有把 Anacod…

【AI论文】潜在区域划分网络:生成建模、表征学习与分类的统一原理 - 实践

【AI论文】潜在区域划分网络:生成建模、表征学习与分类的统一原理 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family…