Online JudgeBzoj3743

Label:换根Dp,维护最长/次长链

题目描述

一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的。

有K个人(分布在K个不同的点)要集中到一个点举行聚会。

聚会结束后需要一辆车从举行聚会的这点出发,把这K个人分别送回去。

请你回答,对于i=1~n,如果在第i个点举行聚会,司机最少需要多少时间把K个人都送回家。

输入

第一行两个数,n,K。

接下来n-1行,每行三个数,x,y,z表示x到y之间有一条需要花费z时间的边。

接下来K行,每行一个数,表示K个人的分布。

输出

输出n个数,第i行的数表示:如果在第i个点举行聚会,司机需要的最少时间。

样例

Input

  1. 5 3
  2. 0
  3. 1
  4. 0
  5. 1 4
  6. 2 5
  7. 4 5
  8. 3 5

Output

  1. 2

题解

对于根节点做聚餐点的情况很容易得出。

\(ans[root]=2*∑^{K}_{i=1}dep[person[i]]-max(dep[person[1..K]])\)

也就是,所有住处的深度之和*2(要往返到其他住处)\(-\)住处的最大深度(可以选择最后去深度最大的那个点,这样它就不用了计两次了)。这样求根节点做聚餐点的情况只用dfs一遍,找一个住处的最大深度即可。


求其他非根节点做聚餐点的情况。

对于它子树内的情况和上面一个求法,但对于子树外很明显要用到换根Dp​。维护一个最长/次长链即可,具体细节见代码。

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. using namespace std;
  4. const int N=500100;
  5. inline int read(){
  6. int x=0;char c=getchar();
  7. while(c<'0'||c>'9')c=getchar();
  8. while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
  9. return x;
  10. }
  11. struct edge{
  12. int to,nxt,d;
  13. }e[2*N];
  14. int head[N],Ecnt,n,m;
  15. inline void link(int u,int v,int d){
  16. e[++Ecnt].to=v,e[Ecnt].d=d,e[Ecnt].nxt=head[u];
  17. head[u]=Ecnt;
  18. }
  19. int cnt[N],son[N],ma1[N],ma2[N],len[N];
  20. /*
  21. cnt[]:子树中住处的个数
  22. ma1/2[]:最长/次长链长度(在第一遍dfs中只包含子树中的链,第二遍dfs中考虑了子树外的链)
  23. son[]:i的最长链由i的哪个儿子son引上来(在第二遍dfs中,如果最长链发生改变,则将son赋值为0,表示在子树外)
  24. len[]:住处的深度总和(第二遍dfs时算上子树外住处离自己的距离总和)
  25. */
  26. bool mark[N];
  27. void dfs(int x,int fa){ //第一遍,处理子树
  28. if(mark[x])cnt[x]=1;
  29. for(register int i=head[x];i;i=e[i].nxt){
  30. int y=e[i].to;if(y==fa)continue;
  31. dfs(y,x);
  32. cnt[x]+=cnt[y],len[x]+=len[y];
  33. if(!cnt[y])continue;
  34. len[x]+=e[i].d;
  35. int nowLink=ma1[y]+e[i].d;
  36. if(nowLink>=ma1[x]){
  37. ma2[x]=ma1[x],ma1[x]=nowLink,
  38. son[x]=y;
  39. }
  40. else if(nowLink>=ma2[x])ma2[x]=nowLink;
  41. }
  42. }
  43. void redfs(int x,int fa){//第二遍,换根。处理子树外
  44. for(register int i=head[x];i;i=e[i].nxt){
  45. int y=e[i].to;if(y==fa)continue;
  46. //将以x为根的所有状态转移到以y为根
  47. len[y]=len[x];
  48. if(cnt[y]==0)len[y]+=e[i].d;//y离所有标记点远了
  49. if(cnt[y]==m)len[y]-=e[i].d;//y离所有标记点近了
  50. int nowLink=(y==son[x]?ma2[x]:ma1[x])+e[i].d;
  51. if(cnt[y]!=m){//!!!注意
  52. if(nowLink>=ma1[y]){
  53. ma2[y]=ma1[y],ma1[y]=nowLink;
  54. son[y]=0;//y此时的最长链在它的子树外
  55. }
  56. else if(nowLink>=ma2[y])ma2[y]=nowLink;
  57. }
  58. redfs(y,x);
  59. }
  60. }
  61. signed main(){
  62. n=read(),m=read();
  63. for(register int i=1;i<n;i++){
  64. int u=read(),v=read(),d=read();
  65. link(u,v,d),link(v,u,d);
  66. }
  67. for(register int i=1;i<=m;i++)mark[read()]=1;
  68. dfs(1,0);
  69. redfs(1,0);
  70. for(register int i=1;i<=n;i++)printf("%lld\n",2*len[i]-ma1[i]);
  71. return 0;
  72. }

update:

一开始下面这个操作没有判(\(cnt[y]!=m\))但在bzoj上也A了,后来做到了重题[COCI2014/2015 Contest#1 F]发现会被下面这个数据搞掉。

  1. if(cnt[y]!=m){//!!!注意
  2. if(nowLink>=ma1[y]){
  3. ma2[y]=ma1[y],ma1[y]=nowLink;
  4. son[y]=0;//y此时的最长链在它的子树外
  5. }
  6. else if(nowLink>=ma2[y])ma2[y]=nowLink;
  7. }
  8. /*
  9. 输入:
  10. 5 2
  11. 2 5 1
  12. 2 4 1
  13. 1 2 2
  14. 1 3 2
  15. 4
  16. 5
  17. 正确输出:
  18. 5
  19. 3
  20. 7
  21. 2
  22. 2
  23. */

[Bzoj3743][Coci2015] Kamp【换根Dp】的更多相关文章

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

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

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

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

  3. [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]

    题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...

  4. 2018.10.15 NOIP训练 水流成河(换根dp)

    传送门 换根dp入门题. 貌似李煜东的书上讲过? 不记得了. 先推出以1为根时的答案. 然后考虑向儿子转移. 我们记f[p]f[p]f[p]表示原树中以ppp为根的子树的答案. g[p]g[p]g[p ...

  5. 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市

    P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...

  6. 小奇的仓库:换根dp

    一道很好的换根dp题.考场上现场yy十分愉快 给定树,求每个点的到其它所有点的距离异或上m之后的值,n=100000,m<=16 只能线性复杂度求解,m又小得奇怪.或者带一个log像kx一样打一 ...

  7. 国家集训队 Crash 的文明世界(第二类斯特林数+换根dp)

    题意 ​ 题目链接:https://www.luogu.org/problem/P4827 ​ 给定一棵 \(n\) 个节点的树和一个常数 \(k\) ,对于树上的每一个节点 \(i\) ,求出 \( ...

  8. Acesrc and Travel(2019年杭电多校第八场06+HDU6662+换根dp)

    题目链接 传送门 题意 两个绝顶聪明的人在树上玩博弈,规则是轮流选择下一个要到达的点,每达到一个点时,先手和后手分别获得\(a_i,b_i\)(到达这个点时两个人都会获得)的权值,已经经过的点无法再次 ...

  9. bzoj 3566: [SHOI2014]概率充电器 数学期望+换根dp

    题意:给定一颗树,树上每个点通电概率为 $q[i]$%,每条边通电的概率为 $p[i]$%,求期望充入电的点的个数. 期望在任何时候都具有线性性,所以可以分别求每个点通电的概率(这种情况下期望=概率 ...

随机推荐

  1. Android开发 retrofit入门讲解 (RxJava模式)

    前言 retrofit除了正常使用以外,还支持RxJava的模式来使用,此篇博客讲解如何使用RxJava模式下的retrofit 依赖 implementation 'com.squareup.ret ...

  2. 校园商铺-2项目设计和框架搭建-10验证controller

    1.新建package:com.csj2018.o2o.web.superadmin 2.建立AreaController.java package com.csj2018.o2o.web.super ...

  3. 配置文件一web.xml

    前言 web.xml中标签的加载顺序:<context-param> > <listener> (spring的相关工作) > filter >servlet ...

  4. Windows taskkill

    TASKKILL [/S system [/U username [/P [password]]]]         { [/FI filter] [/PID processid | /IM imag ...

  5. react 组件的生命周期 超简版

    组件从被创建到被销毁的过程称为组件的 生命周期: 通常,组件的生命周期可以被分为三个阶段:挂载阶段.更新阶段.卸载阶段: 一.挂载阶段 这个阶段组件被创建,执行初始化,并被挂载到DOM中,完成组件的第 ...

  6. SCRIPT7002: XMLHttpRequest: 网络错误 0x2ef3的解决方法

    最近在使用jquery easyui datagrid 对页面布局,发现有时在IE下会接收不到数据并报错: SCRIPT7002: XMLHttpRequest: 网络错误 0x2ef3, 由于出现错 ...

  7. vue-router使用入门

    安装及基本配置 # 安装 npm install vue-router # 使用 import Vue from 'vue' import VueRouter from 'vue-router' Vu ...

  8. USACO 2006 November Gold Fence Repair /// 贪心(有意思)(优先队列) oj23940

    题目大意: 输入N ( 1 ≤ N ≤ 20,000 ) :将一块木板分为n块 每次切割木板的开销为这块木板的长度,即将长度为21的木板分为13和8,则开销为21 接下来n行描述每块木板要求的长度Li ...

  9. ssm项目中使用拦截器加上不生效解决方案

    在很多时候,需要拦截器来帮助我们完成一些特定的工作,比如获取请求的参数,本身在request这种获取数据就是一次磁盘的io, 如果在filter中获取了参数,那么在controller中就不能获取相关 ...

  10. 16-1-es5

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...