P4383 [八省联考 2018] 林克卡特树

米奇妙妙题

题目的主要操作就是断掉一条边再连一条边权为\(0\)的边

我们考虑先不连那些后来加上的边权为\(0\)的边,先把所有的需要断的边都断掉,那么就形成了\(k+1\)个连通块

接下来的任务就是把所有的连通块连接在一起,可以发现,使得答案最大的连接法就是找出每个连通块中的直径后将所有块的直径依次相连,最后的答案就是所有块的直径的长度之和

现在我们就完成了问题的转化,那么现在我们要求的就是把原树分成\(k+1\)个连通块,使得所有块的直径之和最大

那么设\(f(k)\)表示将树分成\(k+1\)块的答案,设\(k=p\)时答案最大,那么显然有当\(k\)增大或减小时\(f(k)\)都会减小或不变

形式化的表达就是\(f(x+1)-f(x)\leq f(x)-f(x-1)\),也就是说对于相邻两点的斜率有\(x\)和\(x-1\)的斜率大于\(x\)和\(x+1\)的斜率

证明:

对于第一种表示方法,可以理解为从\(f(p)\)的方案一步步改成了\(f(k)\),那么显然改的边越多,答案越劣

对于第二种表示方法,可以理解为从\(f(x-1)\)的方案改成\(f(x)\),再从\(f(x)\)改成\(f(x+1)\),既然\(f\)表示的是最优解,那么肯定从\(f(x-1)\)改成\(f(x)\)时会选择最优的方案,从\(f(x)\)改成\(f(x+1)\)只能选剩下的方案中最优的方案,也就是说肯定不会优于从\(f(x-1)\)改成\(f(x)\)

那么我们就可以使用\(wqs\)二分,剩下的就是如何找在当前二分的\(mid\)斜率下的最大切点,也即最大的连通块数

因为我们计算的是每个连通块里的直径,也就是说对于这条直径中的点,它们的度数(指与直径中有多少个点相连)只有\(1\)和\(2\)两种情况,而不是直径中的点,其度数只能是\(0\),但是因为我们在转移时肯定需要将点分成待与父亲相连的点不会再与父亲相连的点,所以稍微整理下这两种东西,我们就可以得出\(dp\)状态了:

\(dp[x][0]\)表示\(x\)不会再相连,当前\(x\)子树内的答案,此时\(x\)的度数为\(0/1/2\),并且此时的\(x\)有两种情况,一种是其是直径中的点,一种是其不是直径中的点

\(dp[x][1]\)表示\(x\)还可以再相连,当前\(x\)子树内的答案,此时\(x\)的度数\(\leq1\),且\(x\)是直径中的点

\(dp[x][2]\)表示\(x\)不会再相连,但是\(x\)会和其两个儿子相连,也就是说\(x\)是其所处连通块中那条^状的直径的那个转折点,事实上\(dp[x][2]\)是属于\(dp[x][0]\)的,但是为了方便转移,单独提出来,且\(x\)是直径中的点

要注意的是因为我们现在在使用\(wqs\)二分,用\(mid\)表示当前二分的斜率,则有\(y=f(x_0)-k\times x_0\),也就是说我们每分出一个连通块答案就需要\(-k\)

那么转移有:

for(int i=1;i<=n;++i) dp[i][0]=dp[i][1]={0,0},dp[i][2]={-mid,1};//初始化
for(int i=head[x],y;i;i=tree[i].nxt) if((y=tree[i].v)!=fa){
dfs(y,x);
dp[x][2]=max(dp[x][2]+dp[y][0],dp[x][1]+dp[y][1]+make_pair(tree[i].val-mid,1)),
dp[x][1]=max(dp[x][1]+dp[y][0],dp[x][0]+dp[y][1]+make_pair(1ll*tree[i].val,0)),
dp[x][0]=dp[x][0]+dp[y][0];
}
dp[x][0]=max(dp[x][0],max(dp[x][1]+make_pair(-mid,1),dp[x][2]));

\(dp\)是\(pair\)类型,\(first\)是答案,\(second\)是满足当前答案的最大的连通块数量

这里就可以比较直观的感受定义了

因为\(dp[x][0]\)还包含了\(x\)不是直径中的点的情况,所以\(dp[i][0]\)的初始化是\(\{0,0\}\)而不是和\(dp[i][2]\)一样的\(\{-mid,1\}\),包括大括号中转移部分,与\(dp[x][0]\)有关的部分转移不用像\(dp[i][2]\)一样要\(-mid\)就是这个原因

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+5;
const ll INF=1e18;
int n,k;
int head[N],cntt;
struct node{
int nxt,v,val;
}tree[N<<1];
void add(int u,int v,int val){
tree[++cntt]={head[u],v,val},head[u]=cntt;
tree[++cntt]={head[v],u,val},head[v]=cntt;
}
ll l,r,mid;
pair<ll,int> dp[N][3];
pair<ll,int> operator + (pair<ll,int> a,pair<ll,int> b){ return {a.first+b.first,a.second+b.second}; }
void dfs(int x,int fa){
for(int i=head[x],y;i;i=tree[i].nxt) if((y=tree[i].v)!=fa){
dfs(y,x);
dp[x][2]=max(dp[x][2]+dp[y][0],dp[x][1]+dp[y][1]+make_pair(tree[i].val-mid,1)),dp[x][1]=max(dp[x][1]+dp[y][0],dp[x][0]+dp[y][1]+make_pair(1ll*tree[i].val,0)),dp[x][0]=dp[x][0]+dp[y][0];
}
dp[x][0]=max(dp[x][0],max(dp[x][1]+make_pair(-mid,1),dp[x][2]));
}
int get(){
for(int i=1;i<=n;++i) dp[i][0]=dp[i][1]={0,0},dp[i][2]={-mid,1};
dfs(1,0);
return max(dp[1][0],max(dp[1][1],dp[1][2])).second;
}
int main(){
scanf("%d%d",&n,&k),++k;
for(int i=1,u,v,w;i<n;++i) scanf("%d%d%d",&u,&v,&w),add(u,v,w),r+=abs(w);
l=-r;
while(l<r){
mid=l+r+1>>1;
if(get()>=k) l=mid;
else r=mid-1;
}
mid=l,get(),printf("%lld",l*k+dp[1][0].first);
return 0;
}

P4383 [八省联考 2018] 林克卡特树的更多相关文章

  1. P4383 [八省联考2018]林克卡特树 树形dp Wqs二分

    LINK:林克卡特树 作为树形dp 这道题已经属于不容易的级别了. 套上了Wqs二分 (反而更简单了 大雾 容易想到还是对树进行联通情况的dp 然后最后结果总和为各个联通块内的直径. \(f_{i,j ...

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

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

  3. P4383 [八省联考2018]林克卡特树lct

    题目链接 题意分析 一句话题意就是 : 让你选出\((k+1)\)条不相交的链 使得这些链的边权总和最大 (这些链可以是点) 我们考虑使用树形\(DP\) \(dp[i][j][0/1/2]\)表示以 ...

  4. P4383 [八省联考2018]林克卡特树lct 树形DP+凸优化/带权二分

    $ \color{#0066ff}{ 题目描述 }$ 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的 ...

  5. LuoguP4383 [八省联考2018]林克卡特树lct

    LuoguP4383 [八省联考2018]林克卡特树lct https://www.luogu.org/problemnew/show/P4383 分析: 题意等价于选择\(K\)条点不相交的链,使得 ...

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

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

  7. luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分)

    luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分) Luogu 题解时间 $ k $ 条边权为 $ 0 $ 的边. 是的,边权为零. 转化成选正好 $ k+1 $ 条链. $ ...

  8. 洛谷 4383 [八省联考2018]林克卡特树lct——树形DP+带权二分

    题目:https://www.luogu.org/problemnew/show/P4383 关于带权二分:https://www.cnblogs.com/flashhu/p/9480669.html ...

  9. [八省联考2018]林克卡特树lct

    题解: zhcs的那个题基本上就是抄这个题的,不过背包的分数变成了70分.. 不过得分开来写..因为两个数组不能同时满足 背包的话就是 $f[i][j][0/1]$表示考虑i子树,取j条链,能不能向上 ...

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

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

随机推荐

  1. 入门Dify平台:工作流节点分析

    要让智能体在实际应用中表现出色,掌握工作流的使用至关重要.今天,我们将深入探讨Dify平台中的各个节点的功能,了解它们的使用方法以及常见的应用场景.通过对这些节点的全面了解,将能够高效地设计和优化智能 ...

  2. 使用Shader画常见的数学函数

    使用Shader画常见的数学函数 本篇博文的灵感来自于Shader Books这一小节:https://thebookofshaders.com/05/?lan=ch 代码运行网站:http://ed ...

  3. nacos(八): sentinel——基本使用

    一.概要 在微服务的架构中,流控是一个重要的任务.sentinel是阿里开源的流量治理组件,针对访问的"资源"或服务路径进行流控,内置了限流.熔断及系统负载保护等功能. senti ...

  4. Effective Java理解笔记系列-第2条-何时考虑用构建器?

    为什么写这系列博客? 在阅读<Effective Java>这本书时,我发现有许多地方需要仔细认真地慢慢阅读并且在必要时查阅相关资料才能彻底搞懂,相信有些读者在阅读此书时也有类似感受:同时 ...

  5. 在IIS Express下部署NuGet私服

    用途 个人开发,部署自己的NuGet pkg. 环境 Win11 IIS Express (轻度使用,不安装IIS,而使用VS预装的IIS Express) VS2022 步骤 开发环境准备 因我拟用 ...

  6. 阅读IDEA生成的equals方法--java进阶day05

    1.IDEA生成的equals方法 虽然我们之前写了equals方法,但IDEA中可以快速生成equals方法,因此,我们要能看懂IDEA生成的equals方法 1.if(this==o) 2.if( ...

  7. 【软件】DVDStyler报错找不到VOB文件

    DVDStyler失败报错找不到VOB文件 零.错误如下 ERR: 2 opening input video file "D:\Minuhy\Desktop\dvd\t\dvd-cache ...

  8. PDA自带有红外扫描头,不用点击焦点就能超高速超精准的扫条码、扫二维码

    参考牛人DelphiTeacher的<PDA扫码?不要慌,只要20行代码!> 摘要: 实现监听器接口 然后在系统中注册该监听器,注册时指定只接收名称为com.kte.scan.result ...

  9. nodejs环境准备

    这是为了针对nodejs使用来进行的环境准备,分出windows和ubuntu两种情况: Windows 环境 安装 Node.js 下载安装包:访问下面nodejs官网: 选择适合 Windows ...

  10. 使用benchmarksql测试数据库处理能力

    我们所处行业的核心应用业务,当前还是传统的OLTP业务,应用系统使用 java 开发,并且不建议使用存储过程,使用 benchmarksql 压测数据库最公平,既可以测试数据库性能,也可以测试JDBC ...