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] 重建计划的更多相关文章

  1. BZOJ 1758 【WC2010】 重建计划

    题目链接:重建计划 这道题现在已经成为一道板子题了…… 这是个非常显然的0-1分数规划,可以二分答案之后树分治判定一下.注意树分治的时候如果使用单调队列,需要把所有儿子预先按最大深度排好序,否则会被扫 ...

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

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

  3. bzoj1758Wc10重建计划——solution

    1758: [Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 4707  Solved: 1200[Submit][Status ...

  4. BZOJ1758: [Wc2010]重建计划

    题解: 这题我居然做了一星期?... 平均值的极值其实也可以算是一种分数规划,只不过分母上b[i]=1 然后我们就可以二分这个值.类似与 HNOI最小圈 如果没有 链的长度的限制的话,我们直接两遍df ...

  5. 【BZOJ1758】【WC2010】重建计划(点分治,单调队列)

    [BZOJ1758][WC2010]重建计划(点分治,单调队列) 题面 BZOJ 洛谷 Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表 ...

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

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

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

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

  8. [WC2010]重建计划 长链剖分

    [WC2010]重建计划 LG传送门 又一道长链剖分好题. 这题写点分治的人应该比较多吧,但是我太菜了,只会长链剖分. 如果你还不会长链剖分的基本操作,可以看看我的长链剖分总结. 首先一看求平均值最大 ...

  9. 蒟蒻的长链剖分学习笔记(例题:HOTEL加强版、重建计划)

    长链剖分学习笔记 说到树的链剖,大多数人都会首先想到重链剖分.的确,目前重链剖分在OI中有更加多样化的应用,但它大多时候是替代不了长链剖分的. 重链剖分是把size最大的儿子当成重儿子,顾名思义长链剖 ...

随机推荐

  1. ffmpeg 调试

    --enable-debug=3 --disable-optimizations --disable-yasm --disable-asm

  2. PSPnet:Pyramid Scene Parsing Network——作者认为现有模型由于没有引入足够的上下文信息及不同感受野下的全局信息而存在分割出现错误的情景,于是,提出了使用global-scence-level的信息的pspnet

    from:https://blog.csdn.net/bea_tree/article/details/56678560 2017年02月23日 19:28:25 阅读数:6094 首先声明,文末彩蛋 ...

  3. python web server gateway interface (wsgi ) notes

    前言: 注:如果需要得到支持批Python3.x以及包含了勘误表,附录,和说明的更新版规范,请查看PEP 3333 摘要: 这篇文档详细说明了一套在web服务器与Python web应用程序(web框 ...

  4. MySQL 单笔订单满6个及以上产品且金额>=300赠送优惠券_20161103

    活动内容: 单笔订单满6个及以上产品(帽子.浴巾除外),金额满赠300元,即赠送300-10元(除帽子.浴巾外)优惠券一张.需求数据:满足条件的用户ID活动时间:11.2-11.5(4天)活动规则:① ...

  5. 树——平衡二叉树插入和查找的JAVA实现

    package com.tomsnail.data.tree; /** * AVL二叉平衡树 * @author tomsnail * @date 2015年3月30日 下午4:35:50 */ pu ...

  6. LED接口

    通常我们都听到别人说DVI接口.VGA接口等,可是这些接口是什么意思,led显示屏厂家小编为您解析其含义与不同之处.   1.DVI接口 DVI接口相校于VGA.HDMI.DP等接口来说体积较大,是目 ...

  7. strlen("汉字")的值是多少

    转自:http://blog.csdn.net/gogor/article/details/4470775 strlen("汉字")的值是多少? 这个问题的答案与系统所采用的字符编 ...

  8. i2c-tools的使用方法及举例

    i2c-tools的使用方法 最近在调试ADV7401,调试的过程难免要反复修改寄存器,然后看结果现象.传统的做法是修改驱动代码寄存器值->编译->下载->运行->看结果,这一 ...

  9. Java面试知识点总结(1)

    1.Java中的原始数据类型都有哪些,它们的大小及对应的封装类是什么? 原始数据类型 大小(byte) 对应封装类型 boolean 1或4 Boolean byte 1 Byte short 2 S ...

  10. mvc 自定义 AuthorizeAttribute 验证逻辑

    public class AuthorizationFilterAttribute : AuthorizeAttribute { Dictionary<string, string> ro ...