Description

一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的。
有K个人(分布在K个不同的点)要集中到一个点举行聚会。
聚会结束后需要一辆车从举行聚会的这点出发,把这K个人分别送回去。
请你回答,对于i=1~n,如果在第i个点举行聚会,司机最少需要多少时间把K个人都送回家。
(注:一个车可以同时乘坐k个人)

HINT

【数据规模】
K <= N <= 500000
1 <= x,y <= N, 1 <= z <= 1000000

Solution

首先一定是一个二次扫描+换根
我的方法:
考虑到,进入一个子树,一定是把这个子树的人都送完再回到子树的根,或者不回到根,就结束了。
所以,套路地,令f[i]表示,以i为根的子树,把所有的关键点遍历到,再回到i的最小花费。
g[i]表示,以i为根的子树,把所有关键点遍历到,不回到i的最小花费。
以1号点为根,
直接树形dp一次可以求出。
注意,子树里没有关键点的f,g都是0
 
然后考虑换根
1号点的答案已经得到,计入ans[1]
换根的时候,fa就是x之前的根,现在x要变成根,
但是,fa的f,g可能进到了x的子树。
所以,设hf[i]为不经过当前根所在的子树,遍历其他关键点,回到i的最小时间。
hg[i]表示,........................,..........,不回到i的最小时间(省略重复内容)
oh[i]表示,除了当前根所在子树外,其他子树里(包括自己)有没有关键点。
每次,更新fa的hg,hf,oh
 
然后,用x的f,g和fa的hg,hf,oh确定ans[x]
细节很多,找std对拍了半天:
1.x的fa找子树的时候,可能找到fa的father,就要用hf[father[fa]]了。
2.第一遍dfs时,可能x是叶子,可能x是关键点,但是子树里没有,可能x及其子树都没有关键点,这些情况f,g都是0
3.换根的时候,考虑x的fa的hg,hf,也要像上面一样考虑。
 
但是,每次换根的时候,要遍历fa的所有儿子。
菊花图直接T的飞起~~~
(但是bzoj数据水)
 

Code

#include<bits/stdc++.h>
using namespace std;
const int N=+;
typedef long long ll;
const ll inf=(1LL*<<);
int n,m;
struct node{
int nxt,to,val;
}e[*N];
int hd[N],cnt;
void add(int x,int y,int z){
e[++cnt].nxt=hd[x];
e[cnt].val=z;
e[cnt].to=y;
hd[x]=cnt;
}
ll dis[N];
bool exi[N];
bool has[N];
ll f[N],g[N];
ll hf[N],hg[N];
bool oh[N];
ll ans[N];
int ff[N];
void dfs(int x,int fa,ll d){
dis[x]=d;
ll sumf=;
bool fl=false;//fl记录是否是叶子
bool bla=false;//bla记录是否有一个子树里有关键点(不包括自己)
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
fl=true;
dfs(y,x,d+e[i].val);
ff[y]=x;
has[x]|=has[y];
if(has[y]){
bla=true;
sumf+=f[y]+e[i].val*;
}
}
if(!has[x]||!fl||!bla) {
f[x]=g[x]=;return;
}
f[x]=sumf;
g[x]=inf;
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(has[y]){
ll now=sumf-f[y]+g[y]-e[i].val;
g[x]=min(g[x],now);
}
}
}
void sol(int x,int fa){
if(x!=){
ll sumf=;
ll valf=;
oh[fa]=;//oh[fa]记得清0,因为可能这个fa会作为多个son的father
if(exi[fa]) oh[fa]=true;
for(int i=hd[fa];i;i=e[i].nxt){
int y=e[i].to;
if(y==x) {
valf=e[i].val;
continue;
}
else if(y==ff[fa]){
if(oh[y]){
oh[fa]=;
sumf+=hf[y]+*e[i].val;
}
}
else{
if(has[y]){
oh[fa]=;
sumf+=f[y]+*e[i].val;
}
}
} hf[fa]=sumf;
hg[fa]=inf;
if(oh[fa]){
bool son=false,bla=false;//son记录除了x是否有儿子。bla同上含义
for(int i=hd[fa];i;i=e[i].nxt){
int y=e[i].to;
if(y==x) continue;
son=true;
if(y==ff[fa]){
if(oh[y]){
bla=true;
ll now=sumf-hf[y]+hg[y]-e[i].val;
hg[fa]=min(hg[fa],now);
}
}
else if(has[y]){
bla=true;
ll now=sumf-f[y]+g[y]-e[i].val;
hg[fa]=min(hg[fa],now);
}
}
if(!son||!bla) hf[fa]=,hg[fa]=;
}
else{
hf[fa]=;
hg[fa]=;
} ll ansf=f[x],ansg=inf;//注意ansg=inf,当有子树至少存在一个关键点,ansg就可以得到正确答案
if(oh[fa]) ansf+=sumf+*valf; for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa){
if(oh[fa]){
ll now=ansf-sumf+hg[fa]-e[i].val;
ansg=min(ansg,now);
}
}
else{
if(has[y]){
ll now=ansf-f[y]+g[y]-e[i].val;
ansg=min(ansg,now);
}
}
} ans[x]=ansg;
}
if(exi[x]&&m==){//全场只有一个关键点,特判,就是0了 ,否则由于ansg的锅,就成了inf
ans[x]=;
}
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
sol(y,x);
} }
int main()
{
scanf("%d%d",&n,&m);int x,y,z;
for(int i=;i<=n-;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}int t;
for(int i=;i<=m;i++){
scanf("%d",&t);
exi[t]=has[t]=;
}
dfs(,,);
ans[]=g[];
sol(,);
for(int i=;i<=n;i++){
printf("%lld\n",ans[i]);
}
return ;
}
 
代码丑,而且会被hack掉。
 

正解:

以某个关键点为根,
对于所有的关键点建一棵虚树tree,所有的权值和是sum
虚树内的节点x的答案,就是sum*2再减去x往下最长链的长度。
虚树外的节点x的答案(一定是虚树某个节点的儿子),就是进入这个虚树的距离,加上进入点在虚树里的答案。
 
换根还是要考虑x的fa的最长链可能经过x。
所以,对于每个点记录一个最长链,一个次长链,(两个链从不同的儿子下去)和它们是从节点的哪一个儿子dp得到的。
rt从fa换到x,
如果fa的最长链不经过x,当前的最长链就是,fa的最长链加上x到fa的边权。
如果fa的最长链经过x,当前的最长链就是,x的最长链,和边权加上fa的次长链取个max
如果fa没有次长链,即fa只有x一个儿子,那么就是x的最长链和边权取个max
 
 
 
 

[Coci2015]Kamp的更多相关文章

  1. 【BZOJ3743】[Coci2015]Kamp 树形DP

    [BZOJ3743][Coci2015]Kamp Description 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的点)要集中到一个点举 ...

  2. bzoj3743 [Coci2015]Kamp 常州模拟赛d6t2

    3743: [Coci2015]Kamp Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 484  Solved: 229[Submit][Status ...

  3. bzoj3743: [Coci2015]Kamp

    首先树dp求出一个点的答案 然后再一遍dfs换根(是叫做换根吗.. 详见代码 #include <iostream> #include <cstdio> #include &l ...

  4. 2018.09.28 bzoj3743: [Coci2015]Kamp(树形dp)

    传送门 这是一道很有意思的题. 我们把所有的关键点都提出来,当成一棵有边权的虚树. 然后发现虚树上除最后不回到虚根的那条路径外外每条边都会被走两遍. 显然要让答案最优,不走的路径应该在虚树的直径上,于 ...

  5. bzoj 3743: [Coci2015]Kamp【树形dp】

    两遍dfs一遍向下,一边向上,分别记录子树内人数a,当前点到所有点的距离b,最大值c和次大值d,最大值子树p 然后答案是2b-c #include<iostream> #include&l ...

  6. [bzoj3743 Coci2015] Kamp(树形dp)

    传送门 Description 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的点)要集中到一个点举行聚会. 聚会结束后需要一辆车从举行聚会的 ...

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

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

  8. bzoj 3743 [Coci2015]Kamp——树形dp+换根

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 树形dp+换根. “从根出发又回到根” 减去 “mx ” . 注意dfsx里真的要改那 ...

  9. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

随机推荐

  1. 20155202张旭 Exp5 MSF基础应用

    20155202张旭 Exp5 MSF基础应用 实践内容 本次实验我使用的攻击方式: 1.针对office软件的主动攻击:--MS10-087: 2.MS10-002漏洞对浏览器攻击 3.针对客户端的 ...

  2. 2017-2018 Exp8 Web基础 20155214

    目录 Exp8 Web基础 实验内容 建站过程 SQL注入 知识点 Exp8 Web基础 实验内容 实验环境 主机 Kali 靶机 Kali 实验工具 后台语言 'PHP' 服务器 'Apache' ...

  3. 20155306 白皎 《网络攻防》 EXP7 网络欺诈技术防范

    20155306 白皎 <网络攻防> EXP7 网络欺诈技术防范 问题回答 (1)通常在什么场景下容易受到DNS spoof攻击 局域网内的攻击以及连接公众场所的共享wifi (2)在日常 ...

  4. Centos 定时任务发送smtp邮件

    接着上一篇文章...... 1.首先创建一个sheel的脚本命令,我是在home文件夹下面创建的命令: touch a.sh 2.编辑a.sh脚本 vim a.sh ,键入键盘   i  键 准备插入 ...

  5. Android开发——进程间通信之Bundle和文件

    0.  前言 不论是Android还是其他操作系统,都会有自己的IPC机制,所谓IPC(Inter-Process Communication)即进程间通信.首先线程和进程是很不同的概念,线程是CPU ...

  6. controlfile作为RMAN的repository时,对 keep time 的测试

    4月2日,首先查看系统状况: SQL> show parameter control NAME                                 TYPE        VALUE ...

  7. ucosii笔记(一)

    .ucosii是按照优先级高低来切换任务执行顺序的抢占式实时系统. 2.在被高优先级的任务抢占时,这个任务会将寄存器的数据(xPSR.PC.LR.R0.R1.R2.R3.R12等的值)存放在该任务自己 ...

  8. CodeForces-1155D Beautiful Array

    Description You are given an array \(a\) consisting of \(n\) integers. Beauty of array is the maximu ...

  9. 如何完全卸载VS2010(亲自体验过) (转)

    1.首先用360卸载,当卸载完成后,提示有残余的话,就强力清除 2,接着,下载IobitUninstaller工具 3.按照下面进行卸载 1.Microsoft .NET Framework 4 框架 ...

  10. cocos2d-x学习记录1——图片显示

    这篇算是cocos2d-x入门篇,显示一张图片即可. 观察工程中HelloWorld的结构,包含AppDelegate和HelloWorldScene两个类文件,AppDelegate中包含基本的处理 ...