luogu4383 [八省联考2018]林克卡特树(带权二分+dp)
题目大意:给定你 n 个点的一棵树 (边有边权,边权有正负)
你需要移除 k 条边,并连接 k 条权值为 0 的边,使得连接之后树的直径最大
题解:
根据 [POI2015]MOD 那道题,显然我们应该找 k+1 条树上不相交的链,求这些链的长度之和最大值
k = 0 部分分:直接求树的直径
k = 1 部分分:把 MOD 那道题 或者点头网那个第一题粘过来就行了
k <= 100 部分分:我们也考虑树形dp
由于我们只需要把长度累加,我们考虑设 f[i][j][0/1/2] 代表以 i 为根的子树中出现了 j 条链, i 的度数为 0/1/2 的子树链的长度和的最大值 xjb 背包下就行, 复杂度 O (n * k * k)
k == 10000
我们设 \(f(x) = f[1][x][0]\), 即钦定链的数量为 x 时的 dp 结果,最后我们要求的答案就是\(f(k + 1)\)
根据莫名其妙的原因,\(f(x)\) 是单峰函数 并且有最大值
显然我们无法在 \(O(n)\) 的时间复杂度内求出这个值。
我们可以考虑给定一个斜率 \(k\),假设求这个斜率的直线与 \(f(x)\) 图像的切点的坐标很容易,我们就可以发现
假设切点是 \((x_0, f(x_0))\), 那么 \(k\) 和 \(x_0\) 之间是一个单调的关系。
根据斜率是单调的这一性质,我们可以考虑二分斜率,每次求出斜率为 mid 时对应的切点位置,如果切点在需要求的 \(k\) 的左边,我们考虑减小斜率,否则考虑增大斜率。
至于怎么求出切点坐标,我们发现 用斜率为 \(k\) 的直线去切曲线 \(f(x)\) 就相当于 用斜率为 0 的直线去切曲线 \(f(x) - kx\),也就是求 \(f(x) - kx\) 的极值点
我们考虑在 dp 时候解除第二维直径数量的限制,反而在 dp 的值中去维护取得最优解时的链的数量, 并且在每加入一条链时在答案贡献中 -= 二分的斜率 k, 最后得到的答案对应的链的数量即为 x, 答案 + k * x 即为 y
#include <cstdio>
#include <vector>
using namespace std;
int n, k;
vector<pair<int, int>> out[300010];
long long mid, ans, pos;
struct dat { int k; long long val; } f[300010][3];
bool operator<(const dat &a, const dat &b) { return a.val != b.val ? (a.val < b.val) : (a.k > b.k); }
dat operator+(const dat &a, const dat &b) { return (dat){a.k + b.k, a.val + b.val}; }
void dfs(int x, int fa)
{
f[x][0] = (dat){0, 0}, f[x][1] = (dat){0, 0}, f[x][2] = (dat){1, -mid};
for (pair<int, int> i : out[x]) if (i.first != fa)
{
int v = i.first; dfs(v, x);
f[x][2] = max(f[x][2] + f[v][0], f[x][1] + f[v][1] + (dat){1, i.second - mid});
f[x][1] = max(f[x][1] + f[v][0], f[x][0] + f[v][1] + (dat){0, i.second});
f[x][0] = f[x][0] + f[v][0];
}
f[x][0] = max(f[x][0], max(f[x][2], f[x][1] + (dat){1, -mid}));
}
long long check()
{
dfs(1, 0), ans = f[1][0].val;
return pos = f[1][0].k;
}
int main()
{
scanf("%d%d", &n, &k), k++;
for (int x, y, z, i = 1; i < n; i++)
{
scanf("%d%d%d", &x, &y, &z);
out[x].push_back(make_pair(y, z));
out[y].push_back(make_pair(x, z));
}
long long l = -1e12, r = -l;
while (l < r)
{
mid = (l + r) >> 1;
if (check() >= k) l = mid + 1;
else r = mid;
}
mid = l, check();
printf("%lld\n", ans + l * k);
return 0;
}
luogu4383 [八省联考2018]林克卡特树(带权二分+dp)的更多相关文章
- [八省联考2018]林克卡特树lct——WQS二分
[八省联考2018]林克卡特树lct 一看这种题就不是lct... 除了直径好拿分,别的都难做. 所以必须转化 突破口在于:连“0”边 对于k=0,我们求直径 k=1,对于(p,q)一定是从p出发,走 ...
- LuoguP4383 [八省联考2018]林克卡特树lct
LuoguP4383 [八省联考2018]林克卡特树lct https://www.luogu.org/problemnew/show/P4383 分析: 题意等价于选择\(K\)条点不相交的链,使得 ...
- luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分)
luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分) Luogu 题解时间 $ k $ 条边权为 $ 0 $ 的边. 是的,边权为零. 转化成选正好 $ k+1 $ 条链. $ ...
- P4383 [八省联考2018]林克卡特树 树形dp Wqs二分
LINK:林克卡特树 作为树形dp 这道题已经属于不容易的级别了. 套上了Wqs二分 (反而更简单了 大雾 容易想到还是对树进行联通情况的dp 然后最后结果总和为各个联通块内的直径. \(f_{i,j ...
- 洛谷P4383 [八省联考2018]林克卡特树lct(DP凸优化/wqs二分)
题目描述 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做“LCT” 的挑 ...
- [八省联考2018]林克卡特树lct
题解: zhcs的那个题基本上就是抄这个题的,不过背包的分数变成了70分.. 不过得分开来写..因为两个数组不能同时满足 背包的话就是 $f[i][j][0/1]$表示考虑i子树,取j条链,能不能向上 ...
- BZOJ5252 八省联考2018林克卡特树(动态规划+wqs二分)
假设已经linkcut完了树,答案显然是树的直径.那么考虑这条直径在原树中是怎样的.容易想到其是由原树中恰好k+1条点不相交的链(包括单个点)拼接而成的.因为这样的链显然可以通过linkcut拼接起来 ...
- 洛谷 4383 [八省联考2018]林克卡特树lct——树形DP+带权二分
题目:https://www.luogu.org/problemnew/show/P4383 关于带权二分:https://www.cnblogs.com/flashhu/p/9480669.html ...
- 洛谷.4383.[八省联考2018]林克卡特树lct(树形DP 带权二分)
题目链接 \(Description\) 给定一棵边带权的树.求删掉K条边.再连上K条权为0的边后,新树的最大直径. \(n,K\leq3\times10^5\). \(Solution\) 题目可以 ...
随机推荐
- 多个div嵌套,获取鼠标所点击的div对象
我选择的是冒泡事件 $(function() { $("#主divID").on("click",function(e) {//主div是必须存在的 //冒泡事 ...
- 273. Integer to English Words数字转为单词
[抄题]: Convert a non-negative integer to its english words representation. Given input is guaranteed ...
- 398. Random Pick Index随机pick函数
[抄题]: Given an array of integers with possible duplicates, randomly output the index of a given targ ...
- Bigtable:一个分布式的结构化数据存储系统
Bigtable:一个分布式的结构化数据存储系统 摘要 Bigtable是一个管理结构化数据的分布式存储系统,它被设计用来处理海量数据:分布在数千台通用服务器上的PB级的数据.Google的很多项目将 ...
- MongoDB 那些坑
MongoDB 是目前炙手可热的 NoSQL 文档型数据库,它提供的一些特性很棒:如自动 failover 机制,自动 sharding,无模式 schemaless,大部分情况下性能也很棒.但是薄荷 ...
- windows编程之内核对象
学好windows编程,理解内核对象还是至关重要的(●'◡'●).闲话不多说,下面先来了解一下关于内核对象的知识: 内核对象(kernel object):内核对象是用于管理进 ...
- code1744 方格染色
稍微复杂一点的划分dp 设f[i][j][k]为第i行前j个k次粉刷正确的最大值 由于每行循环使用,可以去掉第一维,但每次不要忘了清零(卡了好久) f[j][k]=max{ f[u][j-1] + m ...
- Docker 实现的 redis 主从
计划用 Docker 实现 Redis 的主从,简单主从而已.主的名称叫 redis-master 一步步来. 先新建个Dockerfile ,从alpine 开始,比较简单. FROM alpine ...
- 两个线程并发执行以下代码,假设a是全局变量,那么以下输出______是不可能的?
3.两个线程并发执行以下代码,假设a是全局变量,那么以下输出______是不可能的? void foo(){ ++a; printf("%d ",a);}A.3 2 ...
- MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error
今天购物车突然不能添加了,发现redis报错了,重启了一下好了,一会又报错了. 错误信息: MISCONF Redis is configured to save RDB snapshots, but ...