今天模拟赛有一道林克卡特树,完全没有思路

赛后想了一想,不就是求\(k+1\)条不相交的链,使其权值之和最大嘛,傻了。

有一个最裸的\(DP\),设\(f[i][j][k]\)表示在以\(i\)为根的子树中,选了\(j\)条链,\(k=0\)表示\(i\)不在链上,\(k=1\)表示\(i\)是链的一端,\(k=2\)表示\(i\)在链的中间

这样就随便转移了,就是个\(O(nk^2)\)的树上背包

然后呢,又傻了,这能怎么优化?

我先在这里Orz一下大佬BLUESKY007,没有学过wqs二分,发现了\(f\)数组关于\(k\)的单调性,一波二分直接A了 %%%%%%

没错,我们需要用这个单调性来进行优化。据官方题解称,假设你闲着没事,把\(k=0-100\)的表打了一下,你就会发现这个上凸函数,但是如果并没有闲心,那我们就大胆的猜一下。

当\(k\)很小的时候,我们肯定先删负权边,这样最大权值和就增大了。当负权边不够用了怎么办,我们就只能开始删正权边,这种情况貌似比较复杂,先来看看正权边删的很多的情况。随着正权边越删越多,最大权值和肯定有一个下降的趋势,这样随着\(k\)的增大,\(f\)就呈现出一个先增后减的趋势,也许\(f\)是一个上凸函数?猜对啦,确实是的

接下来我们需要一个叫wqs二分的优化方法,它经常被用于这样的问题:有\(n\)个带权物品,用满足一定限制的方法选\(m\)个,使得其权值和取最值,而且权值和的最值是关于\(m\)的凸函数。设在取\(x\)个物品时的权值和为\(f(x)\),那么\(f(x)\)的图像大概长这个样子:



那我们该怎么知道\(f(m)\)呢,因为\(f(x)\)是凸的,考虑用一条直线去切它。就像这样:



这样我们就得到了一条斜率为\(k\),解析式为\(y=kx+b\)的直线,上下移动这条直线,你会发现在切点处的截距\(b\)是最大的:



而且切点处\(b=f(x)-kx\),假设我们能找到最大的\(b\)并顺便记录切点的位置,不就能计算\(f(x)\)的值了吗?观察\(b\)的表达式,发现如果我们给每个物品加上一个附加权值\(-k\),然后求出来的最大权值\(f'(x)\)和\(f(x)-kx\)是等价的,于是\(b_{max}=max\{f'(x)\}\),这个式子没有数量限制,直接\(DP\)就行了,中间顺便记录最佳决策点\((x_{max},b_{max})\)。这样的话,就能算出来\(f(x)=kx_{max}+b_{max}\)。用因为我们知道了\(x_{max}\),拿它跟\(m\)比较,就知道是该增大还是减小斜率\(k\),这也提示了我们可以二分斜率

还有一个比较重要的细节,就是\(b\)的最佳决策点可能不止一个,也就是说当前的这条直线跟图像有多个切点,这样我们便无法得知\(m\)在左边还是右边了。我们可以通过一个策略来解决这个问题,就是取\(x\)最大的最佳决策点,最后直接把\(x_{max}\)带入求出\(f(m)\)就行了

以下是帮助你取得大师之剑的代码(滑稽):

#include <bits/stdc++.h>

using namespace std;

//dp+wqs二分
//首先把问题转化为求树上k+1条不相交路径,使其权值和最大 #define N 300000
#define ll long long
#define INF 10000000000000 //INF不能太大,也不能太小 int n, k, eid, head[N+5];
ll m; struct Edge {
int next, to, w;
}e[2*N+5]; struct DP { //为了方便重载了运算符
ll v;
int cnt;
DP operator + (DP rhs) {
return DP{v+rhs.v, cnt+rhs.cnt};
}
bool operator < (DP rhs) const {
return v < rhs.v || (v == rhs.v && cnt < rhs.cnt);
}
}f[3][N+5], temp; void addEdge(int u, int v, int w) {
e[++eid].next = head[u];
e[eid].to = v;
e[eid].w = w;
head[u] = eid;
} DP Max(int u) {
return max(f[0][u], max(f[1][u], f[2][u]));
} DP newDP(DP &a, ll v0, int cnt0) {
return DP{a.v+v0, a.cnt+cnt0};
} void dp(int u, int fa) {
f[0][u] = DP{0, 0}, f[1][u] = DP{-INF, 0}, f[2][u] = DP{-m, 1};
int i, v, w;
for(i = head[u]; i; i = e[i].next) {
v = e[i].to, w = e[i].w;
if(v == fa) continue;
dp(v, u);
temp = Max(v);
f[2][u] = max(f[2][u]+temp, f[1][u]+max(newDP(f[0][v], w, 0), newDP(f[1][v], w+m, -1)));
f[1][u] = max(f[1][u]+temp, f[0][u]+max(newDP(f[0][v], w-m, +1), newDP(f[1][v], w, 0)));
f[0][u] = f[0][u]+temp;
}
} void check() {
dp(1, 0);
} int main() {
scanf("%d%d", &n, &k); k++;
for(int i = 1, x, y, z; i <= n-1; ++i) {
scanf("%d%d%d", &x, &y, &z);
addEdge(x, y, z), addEdge(y, x, z);
}
ll l = -INF, r = INF, ans; //二分斜率
while(l <= r) {
m = (l+r)>>1;
check();
if(Max(1).cnt < k) r = m-1;
else l = m+1, ans = m;
}
m = ans;
check();
printf("%lld\n", Max(1).v+ans*k);
return 0;
}

再附一道例题

CF739E. Gosha is hunting

题解在这里

wqs二分的更多相关文章

  1. CF739E Gosha is hunting DP+wqs二分

    我是从其他博客里看到这题的,上面说做法是wqs二分套wqs二分?但是我好懒呀,只用了一个wqs二分,于是\(O(nlog^2n)\)→\(O(n^2logn)\) 首先我们有一个\(O(n^3)\)的 ...

  2. 关于WQS二分算法以及其一个细节证明

    应用分析 它的作用就是题目给了一个选物品的限制条件,要求刚好选$m$个,让你最大化(最小化)权值, 然后其特点就是当选的物品越多的时候权值越大(越小). 算法分析 我们先不考虑物品限制条件, 假定我们 ...

  3. [总结] wqs二分学习笔记

    论文 提出问题 在某些题目中,强制规定只能选 \(k\) 个物品,选多少个和怎么选都会影响收益,问最优答案. 算法思想 对于上述描述的题目,大部分都可以通过枚举选择物品的个数做到 \(O(nk^2)\ ...

  4. BZOJ5252 八省联考2018林克卡特树(动态规划+wqs二分)

    假设已经linkcut完了树,答案显然是树的直径.那么考虑这条直径在原树中是怎样的.容易想到其是由原树中恰好k+1条点不相交的链(包括单个点)拼接而成的.因为这样的链显然可以通过linkcut拼接起来 ...

  5. [学习笔记]凸优化/WQS二分/带权二分

    从一个题带入:[八省联考2018]林克卡特树lct——WQS二分 比较详细的: 题解 P4383 [[八省联考2018]林克卡特树lct] 简单总结和补充: 条件 凸函数,限制 方法: 二分斜率,找切 ...

  6. [八省联考2018]林克卡特树lct——WQS二分

    [八省联考2018]林克卡特树lct 一看这种题就不是lct... 除了直径好拿分,别的都难做. 所以必须转化 突破口在于:连“0”边 对于k=0,我们求直径 k=1,对于(p,q)一定是从p出发,走 ...

  7. CF739E Gosha is hunting 【WQS二分 + 期望】

    题目链接 CF739E 题解 抓住个数的期望即为概率之和 使用\(A\)的期望为\(p[i]\) 使用\(B\)的期望为\(u[i]\) 都使用的期望为\(p[i] + u[i] - u[i]p[i] ...

  8. 「学习笔记」wqs二分/dp凸优化

    [学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...

  9. 洛谷P4383 [八省联考2018]林克卡特树lct(DP凸优化/wqs二分)

    题目描述 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做“LCT” 的挑 ...

随机推荐

  1. tablednd onDrap 方法不调用

    场景 使用 tablednd 插件时,onDrap 方法不调用 解决 给tr标签加 id 属性

  2. 开源GIS知识

    ---恢复内容开始--- 2.1.3组件层 数据库组件层按照功能可分为两类:数据管理组件和分析组件. 2.1.3.1数据管理组件 (1)GDAL GDAL(http://www.gdal.org/)是 ...

  3. springboot集成elasticsearch

    在基础阶段学习ES一般是首先是 安装ES后借助 Kibana 来进行CURD 了解ES的使用: 在进阶阶段可以需要学习ES的底层原理,如何通过Version来实现乐观锁保证ES不出问题等核心原理: 第 ...

  4. ButterKnife 牛油刀使用

    一.butterknife介绍 ①官网 butterknife ②Field and method binding for Android Views which uses annotation pr ...

  5. UDK Stat命令

    Stat命令(chs  en)提供了游戏和引擎各个方面的实时统计信息,输入不同参数会在屏幕HUD上显示对应统计数据. 非Shipping版的UDK才会启用STATS宏,统计逻辑才会编译进exe,才能使 ...

  6. 数据库原理 - 序列4 - 事务是如何实现的? - Redo Log解析(续)

    > 本文节选自<软件架构设计:大型网站技术架构与业务架构融合之道>第6.4章节. 作者微信公众号:> 架构之道与术.进入后,可以加入书友群,与作者和其他读者进行深入讨论.也可以 ...

  7. 看到了必须要Mark啊,最全的编程中英文词汇对照汇总(里面有好几个版本的,每个版本从a到d的顺序排列)

    java:  第一章: JDK(Java Development Kit) java开发工具包 JVM(Java Virtual Machine) java虚拟机 Javac  编译命令 java   ...

  8. 课堂练习6--统计txt文本

    统计文本中26个字母的频率: package bao; import java.io.BufferedReader; import java.io.FileReader; import java.io ...

  9. java-环境变量的配置

    java基础教程 链接:https://pan.baidu.com/s/1dGHrkghUJi2lew8dbWlIvg 提取码:87mi

  10. 02-Django框架介绍

    02-Django框架介绍 1.MVC框架介绍 MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式 具有耦合性低.重用性高.生 ...