洛谷P4383 [八省联考2018]林克卡特树lct(DP凸优化/wqs二分)
题目描述
小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战。
游戏中有一个叫做“LCT” 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益;若vi < 0 ,则表示走这条边需要支付- vi 的过路费。小L 需要控制主角Link 切掉(Cut)树上的 恰好K 条边,然后再连接 K 条边权为 0 的边,得到一棵新的树。接着,他会选择树上的两个点p; q ,并沿着树上连接这两点的简单路径从p 走到q ,并为经过的每条边支付过路费/ 获取相应收益。
海拉鲁大陆之神TemporaryDO 想考验一下Link。他告诉Link,如果Link 能切掉 合适的边、选择合适的路径从而使 总收益 - 总过路费最大化的话,就把传说中的大师之剑送给他。
小 L 想得到大师之剑,于是他找到了你来帮忙,请你告诉他,Link 能得到的 总收益 - 总过路费最大是多少。
输入输出格式
输入格式:
从文件lct.in 中读入数据。
输入第一行包含两个正整数N; K,保证0 <= K < N <= 3* 10^5105 。
接下来N - 1 行,每行包含三个整数xi; yi; vi,表示第i 条边连接图中的xi; yi 两点, 它的边权为vi。
输出格式
输出到文件lct.out 中。
输出一行一个整数,表示答案。
输入输出样例
说明
【样例1 解释】
一种可能的最优方案为:切掉(2; 4; ?3) 这条边,连接(3; 4; 0) 这条边,选择(p; q) = (1; 5)。
• 对于10% 的数据,k = 0 ;
• 对于另外10% 的数据,k = 1 ;
• 对于另外15% 的数据,k = 2 ;
• 对于另外25% 的数据,k <= 100 ;
• 对于其他数据,没有特殊约定。
对于全部的测试数据,保证有1 <= N <= 3 * 10^5105 ; 1 <= xi; yi <= N; |vi| <= 10^6106 。
【提示】
题目并不难。
当时在考场上,,只会$k=0$还挂了一个点。。
题目等价于:在树上选择$k+1$条不相交的链,使其权值和最大。
考虑树形DP(以下的$k$均为$k+1$)
一个很直观的想法是用$f[i][j]$表示第$i$个节点,子树中选了$j$条链的最大价值。
但这样是无法转移的,因此我们要考虑到根节点的情况,
令$f[0/1/2][i][j]$表示$i$号节点的子树中选了$j$条链,根节点不在任何一条链中/作为链的端点/作为两条链的端点的最大值。
更新的时候分三种情况讨论。
但是这样复杂度是$O(N*K)$的,考虑继续优化。
看到这种带$k$限制类的问题,我们尝试wqs二分
按照套路,我们观察$f$数组在不同的$k$下的最优解,不难发现函数是上凸的。严格证明不会,自己意会一下吧。。
按照套路,二分一个边权,加到每条边上,我们可以通过控制边权来控制$k$的大小。如果边权都很小,肯定是少选几条链比较优,如果边权比较大,肯定是多选几条优。
按照套路,如果我们二分到一个边权,在这里恰好选了$k$条链,那么这种选法就是最优的。
判断的时候不需要枚举$k$,因此DP一遍的复杂度为$O(N)$,总复杂度为$O(NlogV)$
还有就是这玩意儿二分的边界比较诡异。。。
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#define Pair pair<int, int>
#define int long long
const int MAXN = * 1e5 + ;
using namespace std;
inline int read() {
char c = getchar(); int x = , f = ;
while(c < '' || c > '') {if(c == '-') f = -; c = getchar();}
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * f;
}
struct Node {
int x, y;//x :权值 y:数目
bool operator < (const Node &rhs) const {
return this -> x == rhs.x ? this -> y > rhs.y : this -> x < rhs.x;//tag
}
Node operator + (const Node &rhs) const {
return (Node) {x + rhs.x, y + rhs.y};
}
Node operator + (const int &rhs) const {
return (Node) {x + rhs, y};
}
}f[][MAXN];
int N, K;
struct Edge {
int u, v, w, nxt;
}E[MAXN << ];
int head[MAXN], num = ;
inline void AddEdge(int x, int y, int z) {
E[num] = (Edge) {x, y, z, head[x]};
head[x] = num++;
}
int mid;
Node Plus(Node a) {
return (Node){a.x - mid, a.y + };
}
void dfs(int x, int fa) {
f[][x] = max(f[][x], (Node) {-mid, });
for(int i = head[x]; i != -; i = E[i].nxt) {
int v = E[i].v;
if(v == fa) continue;
dfs(v, x);
f[][x] = max(f[][x] + f[][v], Plus(f[][x] + f[][v] + E[i].w));//把根与子树连起来,会增加一条链
f[][x] = max(f[][x] + f[][v], f[][x] + f[][v] + E[i].w);
f[][x] = f[][x] + f[][v];
//printf("%d %d %d\n", f[2][x].x, f[1][x].x, f[0][x].x);
}
f[][x] = max(f[][x], max(Plus(f[][x]), f[][x]));
}
main() {
#ifdef WIN32
freopen("a.in", "r", stdin);
#endif
memset(head, -, sizeof(head));
N = read(); K = read() + ;
int l = , r = ;
for(int i = ; i < N; i++) {
int x = read(), y = read(), z = read();
AddEdge(x, y, z); AddEdge(y, x, z);
r += abs(z);
}
l = -r;
while(l <= r) {
mid = (l + r) >> ;
memset(f, , sizeof(f));
dfs(, );
if(f[][].y <= K) r = mid - ;
else l = mid + ;
}
mid = l; memset(f, , sizeof(f));
dfs(, );
printf("%lld", f[][].x + mid * K);
return ;
}
洛谷P4383 [八省联考2018]林克卡特树lct(DP凸优化/wqs二分)的更多相关文章
- 洛谷 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\) 题目可以 ...
- dp凸优化/wqs二分学习笔记(洛谷4383 [八省联考2018]林克卡特树lct)
qwq 安利一个凸优化讲的比较好的博客 https://www.cnblogs.com/Gloid/p/9433783.html 但是他的暴力部分略微有点问题 qwq 我还是详细的讲一下这个题+这个知 ...
- P4383 [八省联考2018]林克卡特树lct
题目链接 题意分析 一句话题意就是 : 让你选出\((k+1)\)条不相交的链 使得这些链的边权总和最大 (这些链可以是点) 我们考虑使用树形\(DP\) \(dp[i][j][0/1/2]\)表示以 ...
- P4383 [八省联考2018]林克卡特树lct 树形DP+凸优化/带权二分
$ \color{#0066ff}{ 题目描述 }$ 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的 ...
- P4383 [八省联考2018]林克卡特树 树形dp Wqs二分
LINK:林克卡特树 作为树形dp 这道题已经属于不容易的级别了. 套上了Wqs二分 (反而更简单了 大雾 容易想到还是对树进行联通情况的dp 然后最后结果总和为各个联通块内的直径. \(f_{i,j ...
- LuoguP4383 [八省联考2018]林克卡特树lct
LuoguP4383 [八省联考2018]林克卡特树lct https://www.luogu.org/problemnew/show/P4383 分析: 题意等价于选择\(K\)条点不相交的链,使得 ...
- [八省联考2018]林克卡特树lct——WQS二分
[八省联考2018]林克卡特树lct 一看这种题就不是lct... 除了直径好拿分,别的都难做. 所以必须转化 突破口在于:连“0”边 对于k=0,我们求直径 k=1,对于(p,q)一定是从p出发,走 ...
- luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分)
luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分) Luogu 题解时间 $ k $ 条边权为 $ 0 $ 的边. 是的,边权为零. 转化成选正好 $ k+1 $ 条链. $ ...
随机推荐
- ArcGIS DataStore手册——管理篇
第二章:ArcGIS DataStore管理维护 1.备份管理 备份的目的在于发生原始数据损坏或其他突发情况时,可避免数据丢失,并可快速的使用备份数据来恢复,以保证服务仍可使用. 单机模式下,可使用D ...
- Apache服务器运维笔记(5)----容器的处理顺序
容器在配置文件中是可以多次使用的,同时也可以嵌套使用,但是 Apache 在处理容器时却是有一定顺序的,因此在编写容器配置时需要按照一定的顺序来进行,否则Apache处理的结果很可能不是管理员想要的. ...
- Python 2 和Python 3的区别
print input urlopen print print在版本2的使用方法是: print 'this is version 2' 也可以是 print('this is version 2') ...
- 3 TFRecord样例程序实战
将图片数据写入Record文件 # 定义函数转化变量类型. def _int64_feature(value): return tf.train.Feature(int64_list=tf.train ...
- android测试Code
<!--android:layout_alignParentTop="true"--><com.koooke.platform.View.CenterImage ...
- 【NLP汉语自然语言处理与实践】分词_笔记
一.两种分词标准: 1. 粗粒度. 将词作为最小基本单位.比如:浙江大学. 主要用于自然语言处理的各种应用. 2. 细粒度. 不仅对词汇继续切分,也对词汇内部的语素进行切分.比如:浙江/大学. 主要用 ...
- Doing Research Needs Efforts
What is research? From YouTube Video or baiduyun Links What does not? spend many hours before you ...
- c# HttpWebRequest与HttpWebResponse
[转]c# HttpWebRequest与HttpWebResponse 绝技 如果你想做一些,抓取,或者是自动获取的功能,那么就跟我一起来学习一下Http请求吧. 本文章会对Http请求时的Get和 ...
- 深入理解JNI 邓平凡
深入理解JNI 邓凡平 1)使用的时候 :加载libmedia_jni.so 并接着调用JNI_Onload->register_android_media_MediaScanner动态注册JN ...
- [EffectiveC++]item35:考虑virtual函数以外的其他选择
本质上是说了: Template Pattern & Strategy Pattern 详细见<C++设计模式 23种设计模式.pdf 55页> 宁可要组合 不要继承. ——— ...