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

思维难度低,代码难度高

(或者说是我不太会写代码。。。)

最新文章

  1. 上下箭头选中 选项事件 JS
  2. 三大框架ssh
  3. [ubuntu] ubuntu13.04安装rabbitcvs管理svn
  4. arm驱动linux异步通知与异步IO【转】
  5. MySQL(6):数据操作
  6. Ushare应用
  7. 优化从 App.config 读取配置文件
  8. 逻辑运算符、三元运算符、for循环、stack(栈),heap(堆),方法区,静态域
  9. 软件测试之BUG分析定位概述(QA如何分析定位BUG)
  10. configparser模块(ini配置文件生成模块)
  11. [Luogu 1262] 间谍网络
  12. iOS 微信打开第三方应用(Universal Links 和 URL Schemes)
  13. springboot activiti 配置项详解
  14. Could not find class com.google.gson.Gson
  15. python3 Beautifulsoup &lt;class &#39;bs4.element.ResultSet&#39;&gt; &lt;class &#39;bs4.element.Tag&#39;&gt; 取值
  16. 20155337《网络对抗》Exp5 MSF基础应用
  17. SharePoint 中时间轴 Timeline的实现
  18. hibernate向mysql数据库插入中文显示??
  19. vue使用百度地图
  20. 一个C语言内存管理模块的实现

热门文章

  1. 2-mybatis框架
  2. IP服务-计算机网络
  3. VLAN(虚拟局域网)划分
  4. Intellij IDEA 14代码错误提示如何调出来
  5. fiddler篡改请求数据
  6. 集训Day4
  7. ACM学习历程—HDU5396 Expression(递推 &amp;&amp; 计数)
  8. ACM学习历程—HDU1716 排列2(dfs &amp;&amp; set容器)
  9. 【Lintcode】 035.Reverse Linked List
  10. HL7 V2 分隔符