题意:给定一颗大小为 \(n(n \le 5 \times 10 ^ 4)\) 的树,保证树的生成方式随机,你需要选定两个点 \(x, y\),最小化:

\[\sum\limits_{i = 1} ^ n a_i \times \min(dis_{x, i}, dis_{y, i})
\]

你会发现这个问题很类似 [APIO2015]八邻旁之桥,那么同样的我们可以先思考只有单点的情况。

即考虑如何选定 \(x\) 最小化:

\[\sum\limits_{i = 1} ^ n a_i \times dis_{x, i}
\]

那么是不是只要能快速算出每个点 \(x\) 的 \(w_x = \sum\limits_{i = 1} ^ n a_i \times dis_{x, i}\) 即可呢?

来尝试一下,因为树高是 \(\log n\) 的,因此我们要尽可能地使用和树高有关的做法。

那么根据两点之间的距离公式 \(dis_{x, i} = dep_{x} + dep_i - 2 \times dep_{lca}\),显然 \(dep_x\) 是固定的。

其中最难处理的就是 \(dep_{lca}\) 了,因此我们要想办法固定住 \(dep_{lca}\)。

结合之前树高是 \(\log n\) 的性质,不难发现我们可以一步步向上跳,将每次跳到的点记为 \(y\)。

如果此时 \(y\) 是 \(lca_{x, i}\),显然 \(i\) 就应该是除了 \(x\) 所在子树以外的所有点。

那么那么此时这些点 \(i\) 到 \(x\) 的距离就是其到 \(y\) 的距离在加上 \(y\) 到 \(x\) 的距离。

这部分多与的距离很好维护,直接令 \(S_x = \sum\limits_{i \in x} a_i\),然后减一下乘距离即可。

那么这些点到 \(y\) 的距离怎么维护呢,不难发现实际上这是 \(y\) 的整颗子树到其距离减去 \(x\) 所在子树到 \(y\) 的距离即可。

那么就只需要维护 \(f_x = \sum\limits_{i \in x} a_i \times dis_{x, i}\) 以及 \(g_x = \sum\limits_{i \in x} a_i \times dis_{i, fa_x}\),即可。

上面这两个值通过子树合并即可计算。

通过最开始的流程,不难发现 \(w_x\) 的计算方法。

值得一提的是,上面这个做法本质上使用的是点分治的思想。

那么现在一维的情况已经解决,可以来考虑二维的情况。

和最开始提到的那道题很类似的是,对于选定的两个点 \(x, y\) 一定是从这条链的中点分开一部分全部走去 \(x\),另一部分全部走去 \(y\)。

那么我们可以类似与那道题的做法,断去树中的一条边,两边的树就只需要跑上面哪个一维的子问题了。

但是你会发现的是,如果我们继续重新对两边重新计算 \(w_x\),复杂度还是 \(O(n ^ 2)\) 的,同样的我们还是希望能找到一个和树高有关的做法。

可以继续沿用上面递推的思想,看一看能否先计算出一个点的 \(w_x\) 然后沿着树边往下递推。

可以考虑一个简单的情况,如果 \(x\) 往其一个儿子 \(y\) 走 \(w_y\) 的变化情况。

不难发现会有:\(w_y = w_x + S - 2 \times S_y, S\) 为整颗树的权值和。

那么如果 \(w_y\) 会变小当且仅当 \(S - 2 \times S_y < 0\),移项可得:\(S_y > \frac{S}{2}\)。

可以惊奇地发现对于显然这样的 \(y\) 只会存在一个。

那么如果存在这样的点 \(y\) 就一定可以从当前的根已知往下走直到 \(S - 2 \times S_y > 0\) 为止。

可以发现上述这个过程在数随机生成的情况下是可以保证为 \(O(\log n)\) 的。

那么现在的任务就在于如何计算出一个断边 \((u, v)(fa_v = u)\) 后的 \(w_u, w_v\) 即可。

不难发现有 \(w_v = f_v, w_u = w_u - g_v\)。

并且可以发现断边以后将 \(u\) 做为新树的根只会影响 \(u\) 到根路径上的点的 \(S\) 值,直接暴力修改即可。

于是我们就在 \(O(n \log n)\) 的复杂度下完成了本题,事实上从大佬哪里听说貌似使用动态点分治就可以不依赖于树随机生成的性质,以后学习了动态点分治再说吧。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define int long long
  4. #define rep(i, l, r) for (int i = l; i <= r; ++i)
  5. #define Next(i, u) for (int i = h[u]; i; i = e[i].next)
  6. const int N = 50000 + 5;
  7. const int inf = 1e18;
  8. struct edge {
  9. int v, next;
  10. }e[N << 1];
  11. int n, u, v, tot, top, ans = inf, cnt1, cnt2, h[N], a[N], f[N], g[N], w[N], S[N], fa[N], st[N], dep[N];
  12. int read() {
  13. char c; int x = 0, f = 1;
  14. c = getchar();
  15. while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
  16. while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  17. return x * f;
  18. }
  19. void add(int u, int v) {
  20. e[++tot].v = v, e[tot].next = h[u], h[u] = tot;
  21. e[++tot].v = u, e[tot].next = h[v], h[v] = tot;
  22. }
  23. void dfs(int u, int fa, int topf) {
  24. f[topf] += (dep[u] - dep[topf]) * a[u];
  25. Next(i, u) if(e[i].v != fa) dfs(e[i].v, u, topf);
  26. }
  27. void Prefix(int u, int Fa) {
  28. S[u] = a[u], dep[u] = dep[Fa] + 1, fa[u] = Fa;
  29. Next(i, u) if(e[i].v != Fa) Prefix(e[i].v, u), S[u] += S[e[i].v];
  30. dfs(u, Fa, u), g[u] = f[u] + S[u], w[u] = f[u];
  31. }
  32. void access(int u, int fa, int &cnt, int tmp, int topf) {
  33. cnt = tmp;
  34. Next(i, u) {
  35. int v = e[i].v; if(v == fa) continue;
  36. if(S[topf] - 2 * S[v] < 0) access(v, u, cnt, tmp + S[topf] - 2 * S[v], topf);
  37. }
  38. }
  39. void solve(int u, int Fa) {
  40. Next(i, u) {
  41. int v = e[i].v; if(v == Fa) continue;
  42. st[u] = S[u], S[u] = S[1] - S[v];
  43. for (int j = fa[u], k = u; j; k = j, j = fa[j]) st[j] = S[j], S[j] = S[1] - st[k];
  44. access(v, u, cnt1, f[v], v), access(u, v, cnt2, w[u] - g[v], u);
  45. for (int j = u; j; j = fa[j]) S[j] = st[j];
  46. ans = min(ans, cnt1 + cnt2), solve(v, u);
  47. }
  48. }
  49. signed main() {
  50. n = read();
  51. rep(i, 1, n - 1) u = read(), v = read(), add(u, v);
  52. rep(i, 1, n) a[i] = read();
  53. Prefix(1, 0);
  54. rep(i, 1, n) for (int j = i; fa[j]; j = fa[j]) {
  55. w[i] += f[fa[j]] - g[j] + (dep[i] - dep[fa[j]]) * (S[fa[j]] - S[j]);
  56. }
  57. solve(1, 0);
  58. printf("%lld", ans);
  59. return 0;
  60. }

值得一提的是,当树高期望为 \(\log n\) 时,一个很好运用性质的方式就是从叶子开始往上递推或者从上往下递推。

2020-9-29 T3的更多相关文章

  1. OpenWrt(LEDE)2020.4.29更新 UPnP+NAS+多拨+网盘+DNS优化+帕斯沃 无缝集成+软件包

    交流群:QQ 1030484865 电报:  t_homelede   固件说明 基于Lede OpenWrt R2020.4.8版本(源码截止2020.4.29)Lienol Feed及若干自行维护 ...

  2. 学习 Gin 问题总结 2020.12.29

    学习 Gin 问题总结 2020.12.29 数据绑定与解析 BindXXX,ShouldBindXXX和ShouldBindWith区别 BindXXX 会自动返回信息,输入无效时,在header写 ...

  3. 2020/1/29 PHP代码审计之进一步学习XSS【持续更新】

    0x00 上午学习了XSS漏洞,中午吃饭想了想,还是思考的太浅层了,这种老生常谈的东西对于现在的我意义不大.现在我需要的是思考.于是就有了这个随笔.在本文中,我会持续更新一些XSS的深入思考,payl ...

  4. Test 6.29 T3 小学生

    问题描述 "不错,不错!那么,准备好迎接下一道题了么?"一道白光闪过,CJK 眼前出现了 1e100 个小学生."他们中,有一些人轨了我的机子.现在,我需要你在 1S 之 ...

  5. 2020/1/29 PHP代码审计之XSS漏洞

    0x00 XSS漏洞简介 人们经常将跨站脚本攻击(Cross Site Scripting)缩写为CSS,但这会与层叠样式表(Cascading Style Sheets,CSS)的缩写混淆.因此,有 ...

  6. 2020年AI、CV、NLP顶会最全时间表

    2020年AI.CV.NLP顶会最全时间表 2019-09-01 14:04:19 weixin_38753768 阅读数 40   2020 AI.CV.NLP主流会议时间表,包含会议举办的时间.地 ...

  7. 软路由OpenWrt(LEDE)2020.5.10更新 UPnP+NAS+多拨+网盘+DNS优化

    近期更新:2020.05.10更新-基于OpenWrt R2020.5.9版本,源码截止2020.05.10.   交流群:QQ 1030484865 电报 t.me/t_homelede   版本说 ...

  8. OpenWrt(LEDE)2020.4.12编译 UnPnP+NAS+多拨+网盘+DNS优化+帕斯沃 无缝集成

    固件说明 基于Lede OpenWrt R2020.4.8版本(源码截止2020.4.12)Lienol Feed及若干自行维护的软件包 结合家庭x86软路由场景需要定制 按照家庭应用场景对固件及软件 ...

  9. HomeLede 2020.5.27更新 UPnP+NAS+多拨+网盘+DNS优化+帕斯沃/Clash 无缝集成+软件包

    交流群:QQ 1030484865 电报 t.me/t_homelede   固件说明 基于Lede OpenWrt R2020.5.20版本(源码截止2020.5.27)及若干自行维护的软件包 结合 ...

  10. OpenGL学习日志(2020.4之前)

    咳咳,原本这个日志是本机上随便写的一些记录,也没怎么注意可读性和格式,有用信息密度很小,所以实用价值并不大.暂时由于不可抗因素得先鸽一段落了... 后续的日志会升格为模块化的学习记录,(应该)将会有很 ...

随机推荐

  1. 第二十个知识点:Merkle-Damgaard hash函数如何构造

    第二十个知识点:Merkle-Damgaard hash函数如何构造 这里讲的是MD变换,MD变换的全称为Merkle-Damgaard变换.我们平时接触的hash函数都是先构造出一个防碰撞的压缩函数 ...

  2. 昆泰CH7511B方案|EDP转LVDS资料|CS5211pin to pin 替代CH7511B电路设计

    Chrontel的CH7511B是一种低成本.低功耗的半导体器件,它将嵌入式DisplayPort信号转换为LVDS(低压差分信号).这款创新的DisplayPort接收机带有集成LVDS发射机,专为 ...

  3. CS5265替代LT8711设计TYPEC转HDMI 4K高清投屏方案|LT8711龙迅替代方案

    龙迅LT8711是一款Type-C/DP1.2 to HDMI2.0方案芯片.LT8711HE是一款高性能Type-C/DP1.2至HDMI2.0转换器,设计用于将USB typec或DP1.2源连接 ...

  4. gojs 实用高级用法

    大家,新年好! 历史文章: 数据可视化 gojs 简单使用介绍 gojs 如何实现虚线(蚂蚁线)动画? 本文介绍的是在使用 gojs 制作图的过程中,你可能会碰到的问题的一些解决方案. gojs 是一 ...

  5. Linux配置yum源(离线和在线)

    配置yum源有2种方法,一种是离线yum源,另外一种是在线yum源. 一.离线yum源,基于安装光盘提供的安装仓库. 建立一个属于仓库文件夹 mkdir /media/zidong cd /media ...

  6. JZOJ5405 & AtCoder Grand Contest 001 F. Permutation

    题目大意 给出一个长度为\(n\)的排列\(P\)与一个正整数\(k\). 你需要进行如下操作任意次, 使得排列\(P\)的字典序尽量小. 对于两个满足\(|i-j|>=k\) 且\(|P_i- ...

  7. Pytest_常用执行参数详解(3)

    前面讲了测试用例的执行方式,也认识了 -v  -s 这些参数,那么还有没有其它参数呢?答案肯定是有的,我们可以通过 pytest -h来查看所有可用参数. 从图中可以看出,pytest的参数有很多,但 ...

  8. python call函数

    call()函数本质上是将一个类的实例转换成一个函数,例如下列示例: class Sample: def __init__(self, x, y): self.x = x self.y = y def ...

  9. PowerShell【变量篇】

    PS C:\Users\Administrator> $str='这是一个变量' PS C:\Users\Administrator> $str 这是一个变量 PS C:\Users\Ad ...

  10. jsp使用${}语法,对应的spring后台使用Model

    实现的前提,一定要在jsp文件顶部加上 <%@page isELIgnored="false" %> 如上图${aa}与${bb},是直接使用Model的key值对应的 ...