P6419 COCI2014-2015#1 Kamp

换根 \(dp\) 的 trick。

题面

钦定 \(k\) 个关键点,求每个点出发,访问完所有关键点的距离最小值。

思路

设 \(g_u\) 为从点 \(u\) 出发,访问完子树内所有关键点后,回到点 \(u\) 的距离最小值。

\(s_u\) 为点 \(u\) 子树内关键点个数,\(E(u,v)\) 为边权。

\[g_u=\sum_{v\in u.sons} g_v+ E(u,v)\times 2 \times [s_u>0]
\]

自然我们需要换根 dp 求出每个点作为根的时候的 \(g_u\),设这个答案为 \(f_u\)​​。

\(f\) 为 \(u\) 的父亲。

考虑换根转移:

  1. 若 \(s_u=0\),则 \(f_u=g_f+E(f,u)\times 2\),画图显而易见。
  2. 若 \(k-s_u=0\),则 \(f_u=g_u\),都在 \(u\) 的子树内,也显而易见。
  3. 其他情况,则 \(f_u=f_f\),把 \(u\) 作为根,仔细观察一下我们更新的递推式,你会发现 \(f_u=f_f-(g_u-E(u,f))+(g_u+E(u,f))\),化简即可得。

由于车开到最后一个关键点可以不返回 \(u\) 点,而最小访问距离是可以有多重解法的,肯定存在一种方案使得最后访问最距离 \(u\) 最远的点,这样就可以剩下最大距离不用返回 \(u\)​​ 点。

下文所述的最长链,次长连均为关键点作为链的一端的链。

这个貌似可以使用 dfn 序+线段树维护最长链,单次查询复杂度 \(O(\log n)\),但这里也可以利用换根 dp 求最长链。

下面是利用换根 dp 求最长链的思路。

设 \(u\) 子树内到 \(u\) 的最长链长度为 \(len_u\),来自 \(u\) 的儿子 \(id_u\)。

设 \(u\) 子树内到 \(u\) 的次长链长度为 \(slen_u\),要求与 \(len_u\) 来自的儿子不相同。

\(v\) 为 \(u\) 的儿子,有转移:

  1. 若 \(len_u<len_v+E(u,v)\),则 \(slen_u\gets len_u,len_u\gets len_v+E(u,v),id_u\gets v\)。
  2. 若不满足 1 且 \(slen_u<len_v+E(u,v)\),则 \(slen_u\gets len_v+E(u,v)\)​。

变换 \(len_u\) 的意义为到 \(u\) 点的最长链,\(slen_u\) 的意义为和 \(len_u\) 来自不同的 \(u\)​ 所相接的边的次长链。

易得根的 \(len\) 与 \(slen\) 为原来的值。

设 \(f\) 为 \(u\) 的父亲,考虑从根开始的换根转移:

  1. 若 \(len_u<len_f+E(u,f)\) 且 \(id_f\neq u\),则 \(slen_u\gets len_u,len_u\gets len_f+E(u,f),id_u\gets f\)。
  2. 若 \(len_u<slen_f+E(u,f)\),则 \(len_u\gets slen_f+E(u,f),id_u\gets -1\),此时​无论 \(id_u\) 取何值,都不影响下一步转移。
  3. 若 \(slen_u<len_f+E(u,f)\) 且 \(id_f\neq u\),则 \(slen_u\gets len_f+E(u,f)\)​。
  4. 若 \(slen_u<slen_f+E(u,f)\),则 \(slen_u\gets slen_f+E(u,f)\)。

满足上述转移中最靠前的一条,便可以退出转移。

到这里我们变可以输出答案 \(f_i-len_i\)。

CODE

#include<bits/stdc++.h>
using namespace std; #define ll long long const int maxn=5e5+5; struct Edge
{
int tot;
int head[maxn];
struct edgenode{int to,nxt,val;}edge[maxn*2];
inline void add(int x,int y,int z)
{
tot++;
edge[tot].to=y;
edge[tot].nxt=head[x];
edge[tot].val=z;
head[x]=tot;
}
}T; int n,k;
int s[maxn],id[maxn]; ll dp[maxn],f[maxn],len[maxn],slen[maxn]; inline int Max(int a,int b)
{
if(a<b) return b;
else return a;
}
inline void dfs_fir(int u,int fa)
{
for(int i=T.head[u];i;i=T.edge[i].nxt)
{
int v=T.edge[i].to;
if(v==fa) continue;
dfs_fir(v,u);s[u]+=s[v];
}
for(int i=T.head[u];i;i=T.edge[i].nxt)
{
int v=T.edge[i].to,w=T.edge[i].val;
if(v==fa) continue;
if(!s[v]) continue;
dp[u]+=dp[v]+w*2;
if(len[v]+w>=len[u]) slen[u]=len[u],len[u]=len[v]+w,id[u]=v;
else if(len[v]+w>=slen[u]) slen[u]=len[v]+w;
}
}
inline void dfs_sec(int u,int fa)
{
for(int i=T.head[u];i;i=T.edge[i].nxt)
{
int v=T.edge[i].to,w=T.edge[i].val;
if(v==fa) continue;
if(!s[v]) f[v]=f[u]+w*2,len[v]=len[u]+w;
else if(k-s[v])
{
f[v]=f[u];
if(id[u]!=v&&len[v]<len[u]+w) slen[v]=len[v],len[v]=len[u]+w,id[v]=u;
else if(len[v]<slen[u]+w) slen[v]=len[v],len[v]=slen[u]+w,id[v]=-1;
else if(id[u]!=v&&slen[v]<len[u]+w) slen[v]=len[u]+w;
else if(slen[v]<slen[u]+w) slen[v]=slen[u]+w;
}
else f[v]=dp[v];
dfs_sec(v,u);
}
} int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
T.add(x,y,z),T.add(y,x,z);
}
for(int i=1;i<=k;i++)
{
int x;
scanf("%d",&x);
s[x]=1;
}
dfs_fir(1,0);
f[1]=dp[1];
dfs_sec(1,1);
for(int i=1;i<=n;i++) printf("%lld\n",f[i]-len[i]);
}

后记

这个 trick 相较于数据结构优势在于可以 \(O(1)\),劣势在于不可以在线。

P6419 COCI2014-2015#1 Kamp的更多相关文章

  1. COCI2014/2015 Contest#1 D MAFIJA【基环树最大独立点集】

    T1725 天黑请闭眼 Online Judge:COCI2014/2015 Contest#1 D MAFIJA(原题) Label:基环树,断环+树形Dp,贪心+拓扑 题目描述 最近天黑请闭眼在 ...

  2. 2018-2-6考试(COCI2014/2015 Contest#5)

    T1:FUNGHI(1s,32M,50pts)得分:50 题意:给你8个数组成一个环,要你求出其中连续的4个数,让它们的和最大 题解:暴力求出每一连续4个数之和,比较一下就好 标签:模拟 C++ Co ...

  3. C++算法代码——求数列[coci2014/2015 contest #1]

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?id=1815 题目描述 Mirko在数学课上以一种有趣的方式操作数列,首先,他写下一个数列A ...

  4. [Bzoj3743][Coci2015] Kamp【换根Dp】

    Online Judge:Bzoj3743 Label:换根Dp,维护最长/次长链 题目描述 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的 ...

  5. BZOJ3743 : [Coci2014]Kamp

    d[x][0]表示x点向下走且回到x点的最少代价 d[x][1]表示x点向下走但不回到x点的最少代价 d[x][2]表示x点向下走的最长路 d[x][3]表示x点向下走的次长路 u[x][0]表示x点 ...

  6. bzoj 3743 [ Coci 2015 ] Kamp —— 树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 一开始想到了树形DP,处理一下子树中的最小值,向上的最小值,以及子树中的最长路和向上的 ...

  7. 洛谷 P6419 Kamp 题解

    明天就SX AFO了交篇题解%一下 这题大概是我第一道有独立思考切掉的紫题 之前的都是各种抄借鉴题解 为什么写这题的题解呢?另一个重要的原因是这样的↓ 翻了翻已有题解中的几篇,下面几种情况屡见不鲜 样 ...

  8. 2015 西雅图微软总部MVP峰会记录

    2015 西雅图微软总部MVP峰会记录 今年决定参加微软MVP全球峰会,在出发之前本人就已经写这篇博客,希望将本次会议原汁原味奉献给大家 因为这次是本人第一次写会议记录,写得不好的地方希望各位园友见谅 ...

  9. 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus

    最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错 ...

  10. TFS 2015 敏捷开发实践 – 在Kanban上运行一个Sprint

    前言:在 上一篇 TFS2015敏捷开发实践 中,我们给大家介绍了TFS2015中看板的基本使用和功能,这一篇中我们来看一个具体的场景,如何使用看板来运行一个sprint.Sprint是Scrum对迭 ...

随机推荐

  1. linux 操作系统下安装可视化界面

    一.安装背景 1.小白一只,英文不熟.还很菜,面了几个实施,打击的体无完肤!so,人丑多读书吧. 2.安装环境: VMware + centos7 3.本着不懂就问的原则 开始了--- 二.安装前准备 ...

  2. LaTeX 编译中文文档

    介绍 LaTeX 原生不支持中文.为了添加中文的功能,我们需要引入宏包.XeLaTeX 原生支持中文.不过由于默认使用的字体是英文字体,我们需要设置中文字体之后才能用.不过由于一些原因,在使用 LaT ...

  3. JAVA开发常见问题整理(持续更新)

    maven项目出现:"致命错误: 在类路径或引导类路径中找不到程序包 java.lang"的解决方法 原文地址:https://www.cnblogs.com/xuehuashan ...

  4. 常见的 HTTP Status Codes

    前言 网页开发做久了, 自然而且会接触到许多 status code. 这篇列出一些常见的 status code. 初学者可以把它们学上来. 真的很常见哦. 参考 Wikipedia – List ...

  5. Vs Code, Visual Studio 2022, Angular and Live Server Running Through Https and IP Address

    前言 之前就写过 angular cli, vs code liveserver, vs 2019 iis express 10, vs code kestrel 使用 https + ip. 但写的 ...

  6. OData – OData vs GraphQL

    GraphQL 很火, 很厉害, 但是它和 OData 有本质的区别. 所以并不是说任何一样对比另一个绝对的好. GraphQL is not OData twitter 的讨论 有几个点是我能 Ge ...

  7. 【QT性能优化】QT性能优化之QT性能优化实战 QML优化 QT高性能 QT6系列视频课程 QT6 性能优化实战 QT高性能 QT原理源码 QML优化 GUI绘图原理源码

    QT性能优化实战视频课程 QT6 Widgets高性能应用编程 1.课前考试 2.字符串优化(上) 3.字符串优化(下) 4.绘图优化(上) 5.绘图优化(下)  6.QT界面优化(上) 7.QT界面 ...

  8. Flutter 3.3 正式发布

    Flutter 3 是我们正式为全平台提供支持的一个重量级里程碑,距离它的发布仅过去了三个月,今天让我们有请 Flutter 3.3 正式版!近三个月我们并没有放慢更新迭代的速度--自 Flutter ...

  9. 大模型应用开发初探 : 快速直观感受RAG

    大家好,我是Edison. 上一篇,我们了解了什么如何让一些开源小参数量模型具有函数调用的能力.这一篇,我们来快速了解下RAG(检索增强生成)并通过一个简单的DEMO来直观感受一下它的作用. RAG是 ...

  10. YAML 文件基本语法格式(十四)

    一.YAML 文件基本语法格式 前面我们得 Kubernetes 集群已经搭建成功了,现在我们就可以在集群里面来跑我们的应用了.要在集群里面运行我们自己的应用,首先我们需要知道几个概念. 第一个当然就 ...