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. 速通c++

    文章目录 1.什么是c++. 2什么是面向对象,什么又是面向过程. 3.C++的灵魂,c++的类. 4.如何定义一个类. 5.什么是对象. 6.如何定义一个对象. 直接定义: 在堆里面定义. 删除对象 ...

  2. CANopen学习笔记(三)NMT

    NMT NMT主要用来管理和控制各个节点的状态,具体协议可以分为以下四类: NMT protocol Node guard protocol Heartbeat protocol Bootup pro ...

  3. Linux 网络设备命名规则

    在 Linux 系统中,网络接口的命名规则已经经历了几次重要变化,特别是从传统的以 eth 和 wlan 开头的名称,转变到更现代.更具描述性的命名方式.以下是这些变化的概述: 1. 传统命名约定 在 ...

  4. Prometheus 告警恢复时,怎么获取恢复时的值?

    Prometheus 告警事件中的 $value 表示当前告警触发时的值,但是在告警恢复时,Resolved 事件中的 $value 仍然是最新告警时的值,并非是恢复时的值,这是什么原因和原理?是否有 ...

  5. JMonkeyEngine3 Android 旋转 、放大、缩小一个方块 demo 版本3.5.2-stable

    1. Class,里面是旋转的逻辑,很简陋,可以自己优化 import android.util.Log; import com.jme3.app.SimpleApplication; import ...

  6. 【YashanDB知识库】ycm托管数据库时报错OM host ip:127.0.0.1 is not support join to YCM

    问题现象 托管数据库时检查报错OM的IP是127.0.0.1,不支持托管到YCM OM 问题的风险及影响 导致数据库无法托管监控 问题影响的版本 问题发生原因 安装数据库时修改了OM的监听ip为127 ...

  7. 小忙半个月搞个CKA,可还行,搞完后发现自己被割韭菜了

  8. XAMPP Windows PHP-CGI 代码执行漏洞(CVE-2024-4577) | Goby漏洞预警

    漏洞描述: PHP是一种在服务器端执行的脚本语言,在 PHP 的 8.3.8 版本之前存在命令执行漏洞,由于 Windows 的 "Best-Fit Mapping" 特性,在处理 ...

  9. JavaScript – ECMAScript 版本

    参考 TC39.ECMA-262.ECMAScript 的一些事儿 简史 es3 千禧年后稳定版 es4 革命版本, 最后在 2008 年难产了 es5 2009 年推出, 拿了 es4 一些比较简单 ...

  10. EntityFramework Core并发迁移解决方案

    场景 目前一个项目中数据持久化采用EF Core + MySQL,使用CodeFirst模式开发,并且对数据进行了分库,按照目前颗粒度分完之后,大概有一两百个库,每个库的数据都是相互隔离的. 借鉴了G ...