P6419 COCI2014-2015#1 Kamp
P6419 COCI2014-2015#1 Kamp
换根 \(dp\) 的 trick。
题面
钦定 \(k\) 个关键点,求每个点出发,访问完所有关键点的距离最小值。
思路
设 \(g_u\) 为从点 \(u\) 出发,访问完子树内所有关键点后,回到点 \(u\) 的距离最小值。
\(s_u\) 为点 \(u\) 子树内关键点个数,\(E(u,v)\) 为边权。
\]
自然我们需要换根 dp 求出每个点作为根的时候的 \(g_u\),设这个答案为 \(f_u\)。
\(f\) 为 \(u\) 的父亲。
考虑换根转移:
- 若 \(s_u=0\),则 \(f_u=g_f+E(f,u)\times 2\),画图显而易见。
- 若 \(k-s_u=0\),则 \(f_u=g_u\),都在 \(u\) 的子树内,也显而易见。
- 其他情况,则 \(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\) 的儿子,有转移:
- 若 \(len_u<len_v+E(u,v)\),则 \(slen_u\gets len_u,len_u\gets len_v+E(u,v),id_u\gets v\)。
- 若不满足 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\) 的父亲,考虑从根开始的换根转移:
- 若 \(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\)。
- 若 \(len_u<slen_f+E(u,f)\),则 \(len_u\gets slen_f+E(u,f),id_u\gets -1\),此时无论 \(id_u\) 取何值,都不影响下一步转移。
- 若 \(slen_u<len_f+E(u,f)\) 且 \(id_f\neq u\),则 \(slen_u\gets len_f+E(u,f)\)。
- 若 \(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的更多相关文章
- COCI2014/2015 Contest#1 D MAFIJA【基环树最大独立点集】
T1725 天黑请闭眼 Online Judge:COCI2014/2015 Contest#1 D MAFIJA(原题) Label:基环树,断环+树形Dp,贪心+拓扑 题目描述 最近天黑请闭眼在 ...
- 2018-2-6考试(COCI2014/2015 Contest#5)
T1:FUNGHI(1s,32M,50pts)得分:50 题意:给你8个数组成一个环,要你求出其中连续的4个数,让它们的和最大 题解:暴力求出每一连续4个数之和,比较一下就好 标签:模拟 C++ Co ...
- C++算法代码——求数列[coci2014/2015 contest #1]
题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?id=1815 题目描述 Mirko在数学课上以一种有趣的方式操作数列,首先,他写下一个数列A ...
- [Bzoj3743][Coci2015] Kamp【换根Dp】
Online Judge:Bzoj3743 Label:换根Dp,维护最长/次长链 题目描述 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的 ...
- 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点 ...
- bzoj 3743 [ Coci 2015 ] Kamp —— 树形DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 一开始想到了树形DP,处理一下子树中的最小值,向上的最小值,以及子树中的最长路和向上的 ...
- 洛谷 P6419 Kamp 题解
明天就SX AFO了交篇题解%一下 这题大概是我第一道有独立思考切掉的紫题 之前的都是各种抄借鉴题解 为什么写这题的题解呢?另一个重要的原因是这样的↓ 翻了翻已有题解中的几篇,下面几种情况屡见不鲜 样 ...
- 2015 西雅图微软总部MVP峰会记录
2015 西雅图微软总部MVP峰会记录 今年决定参加微软MVP全球峰会,在出发之前本人就已经写这篇博客,希望将本次会议原汁原味奉献给大家 因为这次是本人第一次写会议记录,写得不好的地方希望各位园友见谅 ...
- 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus
最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错 ...
- TFS 2015 敏捷开发实践 – 在Kanban上运行一个Sprint
前言:在 上一篇 TFS2015敏捷开发实践 中,我们给大家介绍了TFS2015中看板的基本使用和功能,这一篇中我们来看一个具体的场景,如何使用看板来运行一个sprint.Sprint是Scrum对迭 ...
随机推荐
- linux 操作系统下安装可视化界面
一.安装背景 1.小白一只,英文不熟.还很菜,面了几个实施,打击的体无完肤!so,人丑多读书吧. 2.安装环境: VMware + centos7 3.本着不懂就问的原则 开始了--- 二.安装前准备 ...
- LaTeX 编译中文文档
介绍 LaTeX 原生不支持中文.为了添加中文的功能,我们需要引入宏包.XeLaTeX 原生支持中文.不过由于默认使用的字体是英文字体,我们需要设置中文字体之后才能用.不过由于一些原因,在使用 LaT ...
- JAVA开发常见问题整理(持续更新)
maven项目出现:"致命错误: 在类路径或引导类路径中找不到程序包 java.lang"的解决方法 原文地址:https://www.cnblogs.com/xuehuashan ...
- 常见的 HTTP Status Codes
前言 网页开发做久了, 自然而且会接触到许多 status code. 这篇列出一些常见的 status code. 初学者可以把它们学上来. 真的很常见哦. 参考 Wikipedia – List ...
- 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. 但写的 ...
- OData – OData vs GraphQL
GraphQL 很火, 很厉害, 但是它和 OData 有本质的区别. 所以并不是说任何一样对比另一个绝对的好. GraphQL is not OData twitter 的讨论 有几个点是我能 Ge ...
- 【QT性能优化】QT性能优化之QT性能优化实战 QML优化 QT高性能 QT6系列视频课程 QT6 性能优化实战 QT高性能 QT原理源码 QML优化 GUI绘图原理源码
QT性能优化实战视频课程 QT6 Widgets高性能应用编程 1.课前考试 2.字符串优化(上) 3.字符串优化(下) 4.绘图优化(上) 5.绘图优化(下) 6.QT界面优化(上) 7.QT界面 ...
- Flutter 3.3 正式发布
Flutter 3 是我们正式为全平台提供支持的一个重量级里程碑,距离它的发布仅过去了三个月,今天让我们有请 Flutter 3.3 正式版!近三个月我们并没有放慢更新迭代的速度--自 Flutter ...
- 大模型应用开发初探 : 快速直观感受RAG
大家好,我是Edison. 上一篇,我们了解了什么如何让一些开源小参数量模型具有函数调用的能力.这一篇,我们来快速了解下RAG(检索增强生成)并通过一个简单的DEMO来直观感受一下它的作用. RAG是 ...
- YAML 文件基本语法格式(十四)
一.YAML 文件基本语法格式 前面我们得 Kubernetes 集群已经搭建成功了,现在我们就可以在集群里面来跑我们的应用了.要在集群里面运行我们自己的应用,首先我们需要知道几个概念. 第一个当然就 ...