题目链接


解题思路:

1.对于这个Avgvalue=∑e∈sv(e)∣s∣Avgvalue = \frac{\sum_{e\in s}v(e)}{|s|}Avgvalue=∣s∣∑e∈s​v(e)​ 求最大值,我们知道着很明显是一个01分数规划的式子,对于01分数规划问题我们可以通过二分,把求值问题转化为判定问题。
Avgvalue=∑e∈sv(e)∣s∣>=midAvgvalue = \frac{\sum_{e\in s}v(e)}{|s|} >= midAvgvalue=∣s∣∑e∈s​v(e)​>=mid
Avgvalue=∑e∈sv(e)>=∣s∣∗midAvgvalue = \sum_{e\in s}v(e) >= |s| * midAvgvalue=e∈s∑​v(e)>=∣s∣∗mid
Avgvalue=∑e∈sv(e)−∣s∣∗mid>=0Avgvalue = \sum_{e\in s}v(e) - |s| * mid>=0Avgvalue=e∈s∑​v(e)−∣s∣∗mid>=0
那么问题就变成了对于一个midmidmid,我们要求是否存在一条路径(路径权值都减去midmidmid)这条路径的权值和大于或者等于0

2.那么对于上面的问题可以用点分治求解,但是有一个问题就是路径的长度要限制在[L,R][L,R][L,R]之间。

我们最朴实的思想就是分治每一个点求出各个子树中各个深度节点的路径权值和的最大值。如何维护[L,R][L,R][L,R]之间的最大值呢?

我们这么看对于深度为1的点就是在[L−1,R−1][L-1,R-1][L−1,R−1]之间找,对于深度为2的点就是在[L−2,R−2][L-2,R-2][L−2,R−2]之间找,那么就有点像滑动窗口了,就可以用单调队列来维护固定区间最大值。

通过上面的思路,那么对于深度相同的点要放到一起,就是bfsbfsbfs嘛!!

我们先bfs把整个子树的各个点的深度距离全都处理出来再跑单调队列,如果边跑边单调队列会MLEMLEMLE因为要记录的东西太多了!!


#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e5 + 10;
const int N = 1e5 + 10;
const double eps = 1e-6;
typedef pair<double,int> PII;
struct node {int nxt, to;double cost;
}edge[maxn];
int G[N], idx;
int head[N], cnt;
int n, L, R;
double mid;
inline void add(int from, int to, double w) {edge[cnt] = {head[from],to,w};head[from] = cnt ++;
}
bool vis[N];
int max_son[N], siz[N], rt, MX = 1e9, max_node;
void getroot(int u, int fa) {max_son[u] = 0, siz[u] = 1;for(int i = head[u]; ~i; i = edge[i].nxt) {int v = edge[i].to;if(v == fa || vis[v]) continue;getroot(v,u);max_son[u] = max(max_son[u],siz[v]);siz[u] = siz[u] + siz[v];}max_son[u] = max(max_son[u],max_node - siz[u]);if(max_son[u] <= MX) MX = max_son[u], rt = u;
}void rebuild(int u) {vis[u] = 1;for(int i = head[u]; ~i; i = edge[i].nxt) {int v = edge[i].to;if(vis[v]) continue;MX = 1e9, rt = 0;max_node = siz[v];getroot(v,u);G[idx++] = rt;rebuild(rt);}
}int last, top;
int q[maxn], dep[maxn];
double dist[maxn], len[maxn];
bool visq[maxn];inline void bfs(int u, double w) {last = 1, top = 0;q[++top] = u;dist[u] = w;dep[u] = 1; for(int i = last; i <= top; ++ i) {int t = q[i];if(visq[t]) continue;visq[t] = 1;for(int i = head[t]; ~i; i = edge[i].nxt) {int v = edge[i].to;if(vis[v] || visq[v]) continue;q[++top] = v;dist[v] = dist[t] + edge[i].cost;dep[v] = dep[t] + 1;}}for(int i = last; i <= top; ++ i) visq[q[i]] = false;
}
int stk[maxn << 1];
int MXD;
//stk[i] 单调队列里面第i个数是 str[i] 表示长度
inline bool check(int u) {// bfs队列 tip 队头,top队尾// 单调队列 t 是队列的头,w是队列的尾巴 q是队列int t = 1, w = 0, tip = last;for (int i = min(R, dep[q[top]]); i >= 0; --i)//枚举限定区间{int tl = i >= L ? 0 : L - i, tr = R - i;//判断该深度的限定范围 [tl,tr] = [L - i, R - i]while (t <= w && dep[stk[t]] < tl) ++t;//如果队列存在元素,并且队头的长度 已经小于 L - i了踢出单调队列while (tip <= top && dep[q[tip]] < tl) ++tip; //如果队头元素小于 L - i 了踢出bfs队列while (tip <= top && dep[q[tip]] <= tr)//限制len[q[tip]] >= L - i, 了{while (t <= w && dist[stk[w]] + eps <= dist[q[tip]]) -- w; //如果单调队列的尾巴元素比要新加的还小,就踢出去,维护一单调递减的stk[++ w] = q[tip ++];//入队}if (t <= w && len[i] + dist[stk[t]] >= -eps) return true;}return false;
}void dfs(int u, int fa, double val, int dep) {//更新答案len[dep] = max(len[dep],val);MXD = max(MXD,dep);if(dep > R) return;for(int i = head[u]; ~i; i = edge[i].nxt) {int v = edge[i].to;if(v == fa || vis[v]) continue;dfs(v,u,val+edge[i].cost,dep+1);}
}bool Div(int u) {for(int i = 0; i <= MXD; ++ i) len[i] = -1e9;MXD = 0;vis[u] = 1;for(int i = head[u]; ~i; i = edge[i].nxt) {int v = edge[i].to;if(vis[v]) continue;bfs(v,edge[i].cost);if(check(v)) return true;for(int j = last; j <= top; ++ j)len[dep[q[j]]] = max(len[dep[q[j]]],dist[q[j]]);MXD = max(MXD,dep[q[top]]);}for(int i = head[u]; ~i; i = edge[i].nxt) {int v = edge[i].to;if(vis[v]) continue;if(Div(G[idx++])) return true;}return false;
}inline bool Tmp(double mid) {for(int i = 1; i <= n; ++ i)for(int j = head[i]; ~j; j = edge[j].nxt) {edge[j].cost -= mid;}bool f = Div(G[idx++]);for(int i = 1; i <= n; ++ i)for(int j = head[i]; ~j; j = edge[j].nxt) {edge[j].cost += mid;}return f;
}int main() {memset(head,-1,sizeof(head));//............................scanf("%d",&n);for(int i = 0; i <= n; ++ i) len[i] = -1e9;scanf("%d%d",&L,&R);for(int i = 1; i < n; ++ i) {int u, v;double val;scanf("%d%d%lf",&u,&v,&val);add(u,v,val);add(v,u,val); }max_node = n, MX = 1e9;getroot(1,0);G[idx ++] = rt;rebuild(rt);double l = 0.0, r = 1e6;while(r - l > 1e-5) {memset(vis,0,sizeof(vis));idx = 0;mid = (l + r) / 2.0;if(Tmp(mid)) l = mid;else r = mid;}printf("%.3f",l);return 0;
}
/*
6
3 3
1 2 2
2 4 5
2 5 10
1 3 4
3 6 35
2 4
1 2 1
2 3 2
3 4 3
4 5 4
*/

点分治问题 ----------- luoguP2942 [WC2010]重建计划 [点分治 + bfs + 单调队列 + 预处理建树 + 二分 + 01分数规划]相关推荐

  1. [luogu 4292][bzoj 1758][WC2010] 重建计划(点分治 + dp + 单调队列优化 + 启发式合并)

    [WC2010]重建计划 problem solution code problem 洛谷指路 solution 一看那个道路平均价值的式子:AvgValue=∑e∈Sv(e)∣S∣\text{Avg ...

  2. [Luogu P4292] [BZOJ 1758] [WC2010]重建计划

    BZOJ 传送门 洛谷传送门 题目描述 X国遭受了地震的重创, 导致全国的交通近乎瘫痪,重建家园的计划迫在眉睫.X国由NNN个城市组成, 重建小组提出,仅需建立N−1" role=" ...

  3. bzoj1758 [Wc2010]重建计划

    http://www.elijahqi.win/2018/01/20/bzoj1758/ Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U, ...

  4. Bzoj1758: [Wc2010]重建计划

    题面 传送门 Sol 题意就是给你一棵树,有边权 求边数在[L,U][L,U][L, U]内的一条路径,使得边权和除以边数最大,输出这个最大值 二分答案+点分治+单调队列 二分一个答案midmidmi ...

  5. 1758: [Wc2010]重建计划(TLE)

    链接 http://www.lydsy.com/JudgeOnline/problem.php?id=1758 题解? 首先说明这道题我没过. 那为啥要写题解? 因为我确实写的正解啊. 不就是先二分答 ...

  6. 【bzoj1758】[Wc2010]重建计划

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

  7. 分治 —— 01 分数规划

    [概述] 分数规划的一般形式为: 特别的,当  时,称为 01 分数规划 简单来说,就是有一些二元组 (a[i],b[i]),现在从中选择某些二元组,使得  最大或最小 这一类题通用的解法是利用二分法 ...

  8. 【BZOJ1758】重建计划,点分治+单调队列

    Time:2016.08.21 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: UPD 2017.1.18 之前的思路删掉了,因为写的太烂,纯属放屁 刚刚知道新加了一组数据,所以原先 ...

  9. 洛谷P4292:重建计划(点分治、单调队列)

    解析 第一眼:Wow这么水的黑?? 然后写了一发二分套线段树的3log代码上去 T到飞起,只有40- 无奈瞅了一眼标签:单调队列 对啊 于是又写了一个上去 20 - 好啊 然后就摆烂了 qwq 果然黑 ...

最新文章

  1. PingCode Wiki 多人实时协同编辑功能发布
  2. Python正则表达式常用的15个符号整理
  3. 针对这一行业痛点,创新工场投资的潞晨科技发布了大规模并行AI训练系统——“夸父”(Colossal-AI) ,通过多维并行、大规模优化器、自适应任务调度、消除冗余内存、降低能量损耗等方式,旨在打造一个
  4. Release Type
  5. 关于如何使用反编译器,获取源码清单
  6. css3盒模型:IE6混杂模式下的盒模型
  7. 简单的一个用javascript做的'省市区'三级联动效果
  8. html制作搜狗主页,自学htmlcss之仿搜狗主页(示例代码)
  9. 双向链表示意图_java双向链表示意图
  10. ShardingSphere LogicSQL 的生成探索
  11. Spring中使用 InitializingBean
  12. Hibernate,JPA注解@ManyToMany_JoinTable
  13. 【洛谷P5018 对称二叉树】
  14. beautifulsoup_Py之Beautiful Soup:Beautiful Soup 4.2.0的简介、安装、使用方法
  15. Lwip协议详解(基于Lwip 2.1.0)-内存管理
  16. 分享一个好用的网页pdf打印插件
  17. HEX BIN互相转换
  18. 全球ip地址查询与区域判断
  19. Idea主菜单栏不见了怎么找回
  20. 苹果手机微信声音小怎么调大声_苹果手机xr对方听不到我说话,通话质量差的问题...

热门文章

  1. C语言字符串一道比较难的题!_只愿与一人十指紧扣_新浪博客
  2. 论文不公开代码,应该被直接拒稿?
  3. 2021新款 iPad,包邮送一个!10月25日截止
  4. 目标检测中的特征冲突与不对齐问题
  5. Eclipse 最常用的 10 组快捷键,个个牛逼!
  6. DXF 最简单的一个文件生成两个直线一条直线放入BLOCKS中通过INSERT插入 (2)
  7. 论文阅读笔记四十:Deformable ConvNets v2: More Deformable, Better Results(CVPR2018)
  8. SpringBoot实战(四)之使用JDBC和Spring访问数据库
  9. 自己动手做一个小Linux-2
  10. c++ vscode 第三方库_Windows平台配置VSCode的C/C++环境,超清晰