[bzoj 1758] 重建计划
bzoj 1758 重建计划
题意:
给定一棵有边权的树和两个数 \(L, R (L\leq R)\),求一条简单路径,使得这条路径经过的边数在 \(L, R\) 之间且路径经过的边的边权的平均值最大
背景:
NewTrain里面的题
坑了很长时间
题解:
显然是分数规划
二分答案,然后变成判断是否有路径的边权和大于等于 \(0\)
考虑点分治,每一层保留下来每个深度对应的最大边权和,然后因为对于一个子树而言,随着深度增加,合法区间是向左移动的,可以用单调队列维护
复杂度?
对于当前的重心,处理某一棵子树的代价为 \(\max(dep, prev\_dep)\),其中 \(dep\) 表示当前子树的最大深度,\(prev\_dep\) 表示之前处理的子树的最大深度
为了保证复杂度,我们将子树按照深度排序,可以使得 \(dep \geq prev\_dep\) 对于任何子树成立,那么处理一层的代价变为 \(\sum dep \leq size\)
我们发现,不管当前二分的答案是多少,重心的顺序相同,并且对于固定的重心而言,其子树的深度顺序相同,所以都可以预处理,或者直接在点分治内部二分,可以降低常数
(到底是在里面二分快还是在外面二分快啊?好像网上的代码都是在里面二分的,但是栋栋说在外面二分快。。。)
代码:
// Copyright lzt
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef std::pair<int, int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef std::pair<long long, long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i, j, k) for (register int i = (int)(j); i <= (int)(k); i++)
#define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__)
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
x = 10 * x + ch - '0';
ch = getchar();
}
return x * f;
}
const int maxn = 100100;
double MX;
int n, L, R, tot, root, rf, mxdep, nwdep;
int head[maxn], to[maxn << 1], nxt[maxn << 1], len[maxn << 1];
int sz[maxn];
bool vis[maxn];
double res, xx, f[maxn], g[maxn];
vector<pii> vec;
inline void addedge(int x, int y, int l) {
to[++tot] = y; nxt[tot] = head[x]; head[x] = tot; len[tot] = l;
to[++tot] = x; nxt[tot] = head[y]; head[y] = tot; len[tot] = l;
}
inline void dfs1(int u, int pa) {
sz[u] = 1;
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (v == pa || vis[v]) continue;
dfs1(v, u); sz[u] += sz[v];
}
}
inline int getroot(int u, int pa, int S) {
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (v == pa || vis[v]) continue;
if (sz[v] * 2 > S) return getroot(v, u, S);
}
rf = pa;
return u;
}
inline bool cmp (pii x, pii y) {
return sz[x.fi] < sz[y.fi];
}
inline void dfs2(int u, int pa, double l, int d) {
if (d > R) return;
g[d] = max(g[d], l); nwdep = max(nwdep, d);
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (vis[v] || v == pa) continue;
dfs2(v, u, l + len[i] - xx, d + 1);
}
}
int q[maxn];
int h, t;
inline bool ok(int u) {
bool flag = 0;
mxdep = 0;
rep(i, 0, vec.size() - 1) {
nwdep = 0;
dfs2(vec[i].fi, u, vec[i].se - xx, 1);
h = 1, t = 0;
rrep(j, min(R, mxdep), L) {
if (j > mxdep) continue;
double nw = f[j];
while (t >= h && nw >= f[q[t]]) t--;
q[++t] = j;
}
if (t >= h && f[q[h]] >= 0) {
flag = 1;
} else {
rep(j, 1, nwdep) {
double nw = f[L - j];
while (nw >= f[q[t]] && t >= h) t--;
q[++t] = L - j;
while (q[h] + j > R) h++;
if (q[h] <= mxdep && q[h] + j >= L && g[j] + f[q[h]] >= 0) {
flag = 1;
break;
}
}
}
mxdep = max(mxdep, nwdep);
rep(j, 1, nwdep) f[j] = max(f[j], g[j]), g[j] = -1e9;
if (flag) break;
}
rep(j, 1, mxdep) f[j] = -1e9;
return flag;
}
void solve(int u, int pa) {
dfs1(u, pa);
root = getroot(u, pa, sz[u]);
sz[rf] = sz[u] - sz[root];
vec.clear();
for (int i = head[root]; i; i = nxt[i]) {
int v = to[i];
if (vis[v]) continue;
vec.pb(mp(v, len[i]));
}
sort(vec.begin(), vec.end(), cmp);
double le = res, ri = MX;
while (ri - le > 1e-4) {
xx = (le + ri) * 0.5;
if (ok(root)) le = xx;
else ri = xx;
}
res = le;
vis[root] = 1;
for (int i = head[root]; i; i = nxt[i]) {
if (vis[to[i]] || sz[to[i]] <= L) continue;
solve(to[i], root);
}
}
void work() {
n = read(); L = read(), R = read();
rep(i, 1, n - 1) {
int x = read(), y = read(), l = read();
addedge(x, y, l); MX = max(MX, l * 1.0);
}
rep(i, 1, n) f[i] = g[i] = -1e9;
solve(1, 0);
printf("%.3lf\n", res);
}
int main() {
#ifdef LZT
freopen("in", "r", stdin);
#endif
work();
#ifdef LZT
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
}
Review
思维难度低,代码难度高
(或者说是我不太会写代码。。。)
[bzoj 1758] 重建计划的更多相关文章
- BZOJ 1758 【WC2010】 重建计划
题目链接:重建计划 这道题现在已经成为一道板子题了…… 这是个非常显然的0-1分数规划,可以二分答案之后树分治判定一下.注意树分治的时候如果使用单调队列,需要把所有儿子预先按最大深度排好序,否则会被扫 ...
- bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check
[Wc2010]重建计划 Time Limit: 40 Sec Memory Limit: 162 MBSubmit: 4345 Solved: 1054[Submit][Status][Disc ...
- bzoj1758Wc10重建计划——solution
1758: [Wc2010]重建计划 Time Limit: 40 Sec Memory Limit: 162 MBSubmit: 4707 Solved: 1200[Submit][Status ...
- BZOJ1758: [Wc2010]重建计划
题解: 这题我居然做了一星期?... 平均值的极值其实也可以算是一种分数规划,只不过分母上b[i]=1 然后我们就可以二分这个值.类似与 HNOI最小圈 如果没有 链的长度的限制的话,我们直接两遍df ...
- 【BZOJ1758】【WC2010】重建计划(点分治,单调队列)
[BZOJ1758][WC2010]重建计划(点分治,单调队列) 题面 BZOJ 洛谷 Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表 ...
- 「WC2010」重建计划(长链剖分/点分治)
「WC2010」重建计划(长链剖分/点分治) 题目描述 有一棵大小为 \(n\) 的树,给定 \(L, R\) ,要求找到一条长度在 \([L, R]\) 的路径,并且路径上边权的平均值最大 \(1 ...
- 洛谷 P4292 [WC2010]重建计划 解题报告
P4292 [WC2010]重建计划 题目描述 \(X\)国遭受了地震的重创, 导致全国的交通近乎瘫痪,重建家园的计划迫在眉睫.\(X\)国由\(N\)个城市组成, 重建小组提出,仅需建立\(N-1\ ...
- [WC2010]重建计划 长链剖分
[WC2010]重建计划 LG传送门 又一道长链剖分好题. 这题写点分治的人应该比较多吧,但是我太菜了,只会长链剖分. 如果你还不会长链剖分的基本操作,可以看看我的长链剖分总结. 首先一看求平均值最大 ...
- 蒟蒻的长链剖分学习笔记(例题:HOTEL加强版、重建计划)
长链剖分学习笔记 说到树的链剖,大多数人都会首先想到重链剖分.的确,目前重链剖分在OI中有更加多样化的应用,但它大多时候是替代不了长链剖分的. 重链剖分是把size最大的儿子当成重儿子,顾名思义长链剖 ...
随机推荐
- 解决ini-parser解析ini文件中文乱码问题
rickyah/ini-parser 是一个.net 平台解析ini文件的库,当ini文件中含有中文字符时会乱码. 解决:将文件通过Editplus 等文本编辑工具保存为 utf-8 + bom 格式 ...
- tkinter之button
Button按钮,直接上代码: from tkinter import * def gs(): global read s=Label(read,text='昨夜西风凋敝树,堵上高楼,望尽天涯路!', ...
- Cocos2d-x中判断点击是否在触摸屏区域
新建2dx工程. 在HelloWorld头文件加入以下语句: virtual void registerWithTouchDispatcher();//注册触屏事件 覆写register方法 virt ...
- 动态IP下群晖搭建DDNS服务
转载地址:https://www.zimrilink.com/share/dsm_aliddns_server.html 通过阿里云API(php)搭建出DDNS动态域名解析服务器;不同的是本文的方法 ...
- Linux_异常_04_ftp: command not found...
今天在centos上使用ftp命令连接本机的FTP服务器(本机FTP服务使用Vsftpd搭建),出现如下的错误提示:-bash: ftp: command not found 查询相关资料,发现很有可 ...
- hdu-5805 NanoApe Loves Sequence(线段树+概率期望)
题目链接: NanoApe Loves Sequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/131072 ...
- 集训Day4
在bzoj刷了好几天杂题感觉手感不是很好 继续回来集训一下 好几天没更新了啊... bzoj1875 一个无向图,一个人要从起始点走$t$步走到终点,不能沿着刚走过来那条边回去,问有多少种走法 $m ...
- bootstrap框架日期时间 开始日期和结束日期选择
页面表单查询时,常要求要查询一个日期时间段内的数据,若采用bootstrap框架的datetimepicker插件来控制,需要了解怎么个用法:
- AtCoder Beginner Contest 104
A - Rated for Me Time Limit: 2 sec / Memory Limit: 1024 MB Score : 100100 points Problem Statement A ...
- nagios监控windows配置
1.下载并安装windows插件 http://sourceforge.net/projects/nscplus/NSCP-0.4.1.73-x64.msi2.windows端配置 nsclient. ...