题意

自己看.

分析

求这个平均值的最大值就是分数规划,二分一下就变成了求一条长度在[L,R]内路径的权值和最大.有淀粉质的做法但是我没写,感觉常数会很大.这道题可以用长链剖分做.

先对树长链剖分. 我们像做dsu on tree一样先做重儿子,用线段树继承重儿子的全部信息,然后做其他轻儿子

查询的时候枚举一下路径的长度len,一边单点O(1)O(1)O(1)查询长度为len的最大权值,一边线段树O(logn)O(logn)O(logn)查询长度为[L-len,R-len]的区间即可

时间复杂度我不会证(后面有)…反正枚举轻儿子的深度是总共O(n)O(n)O(n)的.所以加上外面的二分,总时间复杂度为O(nlog2n)O(nlog^2n)O(nlog2n).

Upd:Upd:Upd: 枚举轻儿子的深度的时间复杂度证明如下

时间复杂度O(n)O(n)O(n)。

分析如下:

每个点x只会暴力统计其所有轻儿子的信息,而每个轻儿子的信息大小为该轻儿子所在长链长度。

而当递归到x的父节点fa(x)时,若x不是fa(x)的重儿子,则fa(x)会暴力统计大小为x长链长度的信息。

故,每个长链只会对转移的复杂度做一次大小为其长度的贡献。

超强的长链剖分a!!! 证明摘自下面的博客.

学习长链剖分的看这里…博客传送门

CODE

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. char cb[1<<15],*cs=cb,*ct=cb;
  4. #define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
  5. template<class T>inline void read(T &res) {
  6. char ch; int flg = 1; for(;!isdigit(ch=getc());)if(ch=='-')flg=-flg;
  7. for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0'); res*=flg;
  8. }
  9. template<class T>inline void chkmax(T &x, T y) { if(x < y) x = y; }
  10. const int MAXN = 100005;
  11. const double INF = 1e16;
  12. int n, L, R, cnt, fir[MAXN], init_len[MAXN<<1];
  13. struct edge { int to, nxt; double w; }e[MAXN<<1];
  14. inline void add(int u, int v, int wt) {
  15. e[cnt] = (edge) { v, fir[u], 0 }, init_len[cnt] = wt, fir[u] = cnt++;
  16. e[cnt] = (edge) { u, fir[v], 0 }, init_len[cnt] = wt, fir[v] = cnt++;
  17. }
  18. int mxd[MAXN], dep[MAXN], son[MAXN], Eson[MAXN], dfn[MAXN], tmr;
  19. void dfs1(int u, int ff) {
  20. mxd[u] = dep[u] = dep[ff] + 1;
  21. for(int i = fir[u], v; ~i; i = e[i].nxt)
  22. if((v=e[i].to) != ff) {
  23. dfs1(v, u); chkmax(mxd[u], mxd[v]);
  24. if(mxd[v] > mxd[son[u]]) son[u] = v, Eson[u] = i;
  25. }
  26. }
  27. void dfs2(int u, int ff) {
  28. dfn[u] = ++tmr;
  29. if(son[u]) dfs2(son[u], u);
  30. for(int i = fir[u], v; ~i; i = e[i].nxt)
  31. if((v=e[i].to) != ff && v != son[u])
  32. dfs2(v, u);
  33. }
  34. int num[MAXN];
  35. double dis[MAXN], mx[MAXN<<2];
  36. void build(int i, int l, int r) {
  37. mx[i] = -INF;
  38. if(l == r) { num[l] = i; return; }
  39. int mid = (l + r) >> 1;
  40. build(i<<1, l, mid);
  41. build(i<<1|1, mid+1, r);
  42. }
  43. void modify(int i, int l, int r, int x, double val) {
  44. chkmax(mx[i], val);
  45. if(l == r) return;
  46. int mid = (l + r) >> 1;
  47. if(x <= mid) modify(i<<1, l, mid, x, val);
  48. else modify(i<<1|1, mid+1, r, x, val);
  49. }
  50. double query(int i, int l, int r, int x, int y) {
  51. if(x > y) return -INF;
  52. if(l == x && r == y) return mx[i];
  53. int mid = (l + r) >> 1;
  54. if(y <= mid) return query(i<<1, l, mid, x, y);
  55. else if(x > mid) return query(i<<1|1, mid+1, r, x, y);
  56. else return max(query(i<<1, l, mid, x, mid), query(i<<1|1, mid+1, r, mid+1, y));
  57. }
  58. double tmp[MAXN];
  59. bool solve(int u, int ff) {
  60. modify(1, 1, n, dfn[u], dis[u]);
  61. if(son[u]) {
  62. dis[son[u]] = dis[u] + e[Eson[u]].w;
  63. if(solve(son[u], u)) return 1;
  64. }
  65. for(int i = fir[u], v; ~i; i = e[i].nxt)
  66. if((v=e[i].to) != ff && v != son[u]) {
  67. dis[v] = dis[u] + e[i].w;
  68. if(solve(v, u)) return 1;
  69. for(int j = 1; j <= mxd[v]-dep[u]; ++j) {
  70. tmp[j] = mx[num[dfn[v]+j-1]];
  71. if(j <= R) {
  72. double temp = query(1, 1, n, dfn[u] + max(L-j, 0), dfn[u] + min(R-j, mxd[u]-dep[u]));
  73. if(tmp[j] + temp - 2 * dis[u] >= 0) return 1;
  74. }
  75. }
  76. for(int j = 1; j <= mxd[v]-dep[u]; ++j)
  77. modify(1, 1, n, dfn[u]+j, tmp[j]);
  78. }
  79. return query(1, 1, n, dfn[u]+L, dfn[u]+min(R, mxd[u]-dep[u]))-dis[u] >= 0;
  80. }
  81. inline bool judge(double mid) {
  82. for(int i = 0; i < cnt; ++i)
  83. e[i].w = init_len[i] - mid;
  84. build(1, 1, n);
  85. return solve(1, 0);
  86. }
  87. int main() {
  88. memset(fir, -1, sizeof fir);
  89. read(n), read(L), read(R);
  90. for(int i = 1, x, y, z; i < n; ++i)
  91. read(x), read(y), read(z), add(x, y, z);
  92. dfs1(1, 0), dfs2(1, 0);
  93. double l = 0, r = 1e6, mid;
  94. while(r - l > (1e-4)) {
  95. mid = (l + r) / 2;
  96. if(judge(mid)) l = mid;
  97. else r = mid;
  98. }
  99. printf("%.3f\n", l);
  100. }

CODE2

把二分转成迭代后直接洛谷rank 1了…

迭代就是随便取一个值作为mid,带进去算后得到更优的答案,然后把更优的答案作为mid继续迭代下去…直白点就是向答案逼近.

然后初值取一个适中的数就跑的超快了…感觉相当于没有了二分的那一个log

那分数规划都可以用迭代咯…

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. char cb[1<<15],*cs=cb,*ct=cb;
  4. #define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
  5. template<class T>inline void read(T &res) {
  6. char ch; int flg = 1; for(;!isdigit(ch=getchar());)if(ch=='-')flg=-flg;
  7. for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0'); res*=flg;
  8. }
  9. template<class T>inline void chkmax(T &x, T y) { if(x < y) x = y; }
  10. const int MAXN = 100005;
  11. const double INF = 1e16;
  12. int n, L, R, cnt, fir[MAXN], init_len[MAXN<<1];
  13. struct edge { int to, nxt; double w; }e[MAXN<<1];
  14. inline void add(int u, int v, int wt) {
  15. e[cnt] = (edge) { v, fir[u], 0 }, init_len[cnt] = wt, fir[u] = cnt++;
  16. e[cnt] = (edge) { u, fir[v], 0 }, init_len[cnt] = wt, fir[v] = cnt++;
  17. }
  18. int mxd[MAXN], dep[MAXN], son[MAXN], Eson[MAXN], dfn[MAXN], tmr;
  19. void dfs1(int u, int ff) {
  20. mxd[u] = dep[u] = dep[ff] + 1;
  21. for(int i = fir[u], v; ~i; i = e[i].nxt)
  22. if((v=e[i].to) != ff) {
  23. dfs1(v, u); chkmax(mxd[u], mxd[v]);
  24. if(mxd[v] > mxd[son[u]]) son[u] = v, Eson[u] = i;
  25. }
  26. }
  27. void dfs2(int u, int ff) {
  28. dfn[u] = ++tmr;
  29. if(son[u]) dfs2(son[u], u);
  30. for(int i = fir[u], v; ~i; i = e[i].nxt)
  31. if((v=e[i].to) != ff && v != son[u])
  32. dfs2(v, u);
  33. }
  34. int num[MAXN];
  35. double dis[MAXN];
  36. struct node {
  37. double x; int y; //x:最大路径和 y:边数
  38. node(){}
  39. node(double xx, int yy):x(xx), y(yy){}
  40. inline bool operator <(const node &o)const { return x < o.x; }
  41. }Ans, tmp[MAXN], mx[MAXN<<2];
  42. void build(int i, int l, int r) {
  43. mx[i] = node(-INF, 0);
  44. if(l == r) { num[l] = i; return; }
  45. int mid = (l + r) >> 1;
  46. build(i<<1, l, mid);
  47. build(i<<1|1, mid+1, r);
  48. }
  49. void modify(int i, int l, int r, int x, node val) {
  50. chkmax(mx[i], val);
  51. if(l == r) return;
  52. int mid = (l + r) >> 1;
  53. if(x <= mid) modify(i<<1, l, mid, x, val);
  54. else modify(i<<1|1, mid+1, r, x, val);
  55. }
  56. node query(int i, int l, int r, int x, int y) {
  57. if(x > y) return node(-INF, 0);
  58. if(l == x && r == y) return mx[i];
  59. int mid = (l + r) >> 1;
  60. if(y <= mid) return query(i<<1, l, mid, x, y);
  61. else if(x > mid) return query(i<<1|1, mid+1, r, x, y);
  62. else return max(query(i<<1, l, mid, x, mid), query(i<<1|1, mid+1, r, mid+1, y));
  63. }
  64. void solve(int u, int ff) {
  65. modify(1, 1, n, dfn[u], node(dis[u], dep[u]));
  66. if(son[u]) dis[son[u]] = dis[u] + e[Eson[u]].w, solve(son[u], u);
  67. for(int i = fir[u], v; ~i; i = e[i].nxt)
  68. if((v=e[i].to) != ff && v != son[u]) {
  69. dis[v] = dis[u] + e[i].w, solve(v, u);
  70. for(int j = 1; j <= mxd[v]-dep[u]; ++j) {
  71. tmp[j] = mx[num[dfn[v]+j-1]];
  72. if(j <= R) {
  73. node temp = query(1, 1, n, dfn[u] + max(L-j, 0), dfn[u] + min(R-j, mxd[u]-dep[u]));
  74. chkmax(Ans, node(tmp[j].x + temp.x - 2 * dis[u], tmp[j].y + temp.y - 2*dep[u]));
  75. }
  76. }
  77. for(int j = 1; j <= mxd[v]-dep[u]; ++j)
  78. modify(1, 1, n, dfn[u]+j, tmp[j]);
  79. }
  80. node temp = query(1, 1, n, dfn[u]+L, dfn[u]+min(R, mxd[u]-dep[u]));
  81. temp.x -= dis[u]; temp.y -= dep[u];
  82. chkmax(Ans, temp);
  83. }
  84. inline node judge(double mid) {
  85. for(int i = 0; i < cnt; ++i)
  86. e[i].w = init_len[i] - mid;
  87. build(1, 1, n);
  88. Ans = node(-INF, 0);
  89. solve(1, 0);
  90. return Ans;
  91. }
  92. int main() {
  93. memset(fir, -1, sizeof fir);
  94. read(n), read(L), read(R);
  95. for(int i = 1, x, y, z; i < n; ++i)
  96. read(x), read(y), read(z), add(x, y, z);
  97. dep[0] = -1; dfs1(1, 0), dfs2(1, 0);
  98. double mid = 600000;
  99. while(1) { //高级操作
  100. node now = judge(mid);
  101. double ans = (now.x + mid*now.y) / now.y; //把y条边减去的mid加回来,再算一次平均值
  102. if(fabs(ans-mid) < 1e-3) break;
  103. mid = ans;
  104. }
  105. printf("%.3f\n", mid);
  106. }

BZOJ 1758 / Luogu P4292 [WC2010]重建计划 (分数规划(二分/迭代) + 长链剖分/点分治)的更多相关文章

  1. bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check

    [Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 4345  Solved: 1054[Submit][Status][Disc ...

  2. BZOJ.1758.[WC2010]重建计划(分数规划 点分治 单调队列/长链剖分 线段树)

    题目链接 BZOJ 洛谷 点分治 单调队列: 二分答案,然后判断是否存在一条长度在\([L,R]\)的路径满足权值和非负.可以点分治. 对于(距当前根节点)深度为\(d\)的一条路径,可以用其它子树深 ...

  3. BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP

    题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...

  4. [WC2010]重建计划(分数规划+点分治+单调队列)

    题目大意:给定一棵树,求一条长度在L到R的一条路径,使得边权的平均值最大. 题解 树上路径最优化问题,不难想到点分治. 如果没有长度限制,我们可以套上01分数规划的模型,让所有边权减去mid,求一条路 ...

  5. 洛谷 P4292 [WC2010]重建计划 解题报告

    P4292 [WC2010]重建计划 题目描述 \(X\)国遭受了地震的重创, 导致全国的交通近乎瘫痪,重建家园的计划迫在眉睫.\(X\)国由\(N\)个城市组成, 重建小组提出,仅需建立\(N-1\ ...

  6. 「WC2010」重建计划(长链剖分/点分治)

    「WC2010」重建计划(长链剖分/点分治) 题目描述 有一棵大小为 \(n\) 的树,给定 \(L, R\) ,要求找到一条长度在 \([L, R]\) 的路径,并且路径上边权的平均值最大 \(1 ...

  7. 洛谷 P4292 - [WC2010]重建计划(长链剖分+线段树)

    题面传送门 我!竟!然!独!立!A!C!了!这!道!题!incredible! 首先看到这类最大化某个分式的题目,可以套路地想到分数规划,考虑二分答案 \(mid\) 并检验是否存在合法的 \(S\) ...

  8. 【BZOJ 1758】【WC 2010】重建计划 分数规划+点分治+单调队列

    一开始看到$\frac{\sum_{}}{\sum_{}}$就想到了01分数规划但最终还是看了题解 二分完后的点分治,只需要维护一个由之前处理过的子树得出的$tb数组$,然后根据遍历每个当前的子树上的 ...

  9. P4292 [WC2010]重建计划 点分治+单调队列

    题目描述 题目传送门 分析 看到比值的形式就想到 \(01分数规划\),二分答案 设当前的值为 \(mids\) 如果存在\(\frac{\sum _{e \in S} v(e)}{|S|} \geq ...

随机推荐

  1. (转)新手入局 你必须要知道的四类Equity

    许多人缠着我教他们打牌,开始几乎所有的问题都是问,你都玩什么牌. 这个话外行又很难解释,想来想去,我这样总结给他们(我也忘记自己过去有没有说过,我觉得总结的挺好的,只怕初学者听着又和天书一样了). 是 ...

  2. 【转帖】Linux和GNU系统

    Linux和GNU系统 Richard Stallman 著 http://www.gnu.org/gnu/linux-and-gnu.zh-cn.html 更多信息,请同时参看GNU/Linux常见 ...

  3. django进阶版4

    目录 1 Auth模块是什么 2 auth模块常用方法 authenticate() login(HttpRequest, user) logout(request) is_authenticated ...

  4. 代理、反射、注解、hook

    代理 通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,扩展目标对象的功能. 代理对象拦截真实对象的方法调用,在真实对象调用前/后实现自己的逻辑调用 这里使用到编程中的一个思想:不 ...

  5. signalfx的中间件监控指标so cool

    signalfx的中间件监控指标so cool www.jianshu.com   对于我们做运维的来说,监控是最基本的东西,不过在初创公司很多计划是跟不上项目架构变化的,项目中会不断加入各种服务和组 ...

  6. react中数据持久化缓存redux-persist

    一.安装redux-persist: npm install redux-persist --save 二..babelrc中增加redux-persist配置: "plugins" ...

  7. luogu题解 P2860[USACO冗余路径Redundant Paths] 缩点+桥

    题目链接 https://www.luogu.org/problemnew/show/P2860 https://www.lydsy.com/JudgeOnline/problem.php?id=17 ...

  8. phpcms修改重置后台账号和密码

    通过Phpmyadmin等工具,打开数据库中找到v9_admin表: 把password字段值改为: 0b817b72c5e28b61b32ab813fd1ebd7f再把encrypt字段值改为: 3 ...

  9. vue中的常用三元

    点击事件的三元 <el-button type="primary" @click="edit == 'mod' ? sureModify() : submit()& ...

  10. conda查找安装包的版本以及安装特定版本的包

    如下图 想要安装特定版本的torchvision,然后conda search torchvision,能够列出conda云上所有的安装包 然后,安装包的时候,conda install 包名=版本就 ...