题目传送门

题意:给出一个有$N$个点的树,你最开始在$1$号点,经过第$i$条边需要花费$w_i$的时间。每条边只能被经过$2$次。求出到达除$1$号点外所有点的最早时间的最小平均值。$N \leq 10^5 , w \leq 1000$


设$f_i$表示以第$i$个点为子树的最小总时间,考虑由儿子向父亲合并,额外定义$dis_i$为$i$到其父亲的边的边权,$t_i$表示从$t$的父亲走完根节点为$t$的子树再回到$t$的时间,也就等于$(\text{子树边权和+与父亲相连的边的边权})\times 2$,再定义$size_i$表示以$i$为根节点的子树的点数。可以$t_i$与$size_i$都是很容易从儿子向父亲合并的。

设我们正在算点$x$的答案,其儿子为$y_1,y_2...y_k$,且它们的答案已经算出来了。那么它的父亲的答案也就是$\sum\limits_{i=1}^k (f_{y_i}+dis_i \times size_i) + \sum\limits_{i=1}^k t_{p_i} \times (size_x - 1 - \sum\limits_{j=1}^i size_{p_i})$,其中$p_1,p_2...p_k$是一个$y_1,y_2...y_k$的排列,因为子树的选择是无序的,而在选择某个子树的时候,剩下没有选的所有点都需要等待这棵子树遍历完。

那么现在我们的任务转变为了找到一个最优的$p_1,p_2...p_k$的选择。考虑这个排列可能与排序有关,所以我们使用邻项交换的方法分析是否具有贪心策略。考虑相邻两个元素$p_i,p_i+1$,因为交换对于其他元素的答案是没有影响的,所以我们只需要考虑$p_i$与$p_{i+1}$的差别,将其他的设为$W$。

当我们的顺序是$p_i,p_{i+1}$时,答案是$f_{p_i}+t_{p_i} \times size_{p_{i+1}}+f_{p_{i+1}}+W$,而当顺序为$p_{i+1},p_i$时答案为$f_{p_{i+1}}+t_{p_{i+1}} \times size_{p_i}+f_{p_i}+W$。我们令第一种方案优于第二种方案,所以$f_{p_i}+t_{p_i} \times size_{p_{i+1}}+f_{p_{i+1}}+W < f_{p_{i+1}}+t_{p_{i+1}} \times size_{p_i}+f_{p_i}+W$,可以得到$t_{p_i} \times size_{p_{i+1}} < t_{p_{i+1}} \times size_{p_i}$。所以我们使用这个公式进行排序,就可以得到最优的方案。

 #include<bits/stdc++.h>
 #define ld long double
 #define MAXN 500010
 #define int long long
 using namespace std;

 inline int read(){
     ;
     ;
     char c = getchar();
     while(!isdigit(c)){
         if(c == '-')
             f = ;
         c = getchar();
     }
     while(isdigit(c)){
         a = (a << ) + (a << ) + (c ^ ');
         c = getchar();
     }
     return f ? -a : a;
 }

 struct Edge{
     int end , upEd , w;
 }Ed[MAXN];
 int head[MAXN] , siz[MAXN] , T[MAXN] , N , cntEd , forC;
 ld dp[MAXN];

 bool cmp(int a , int b){
     return T[a] * siz[b] < T[b] * siz[a];
 }

 inline void addEd(int a , int b , int c){
     Ed[++cntEd].end = b;
     Ed[cntEd].upEd = head[a];
     Ed[cntEd].w = c;
     head[a] = cntEd;
 }

 void dfs(int now){
     siz[now] = ;
     vector < int > v;
     for(int i = head[now] ; i ; i = Ed[i].upEd)
         if(!siz[Ed[i].end]){
             dfs(Ed[i].end);
             siz[now] += siz[Ed[i].end];
             T[Ed[i].end] += Ed[i].w << ;
             dp[Ed[i].end] += Ed[i].w * siz[Ed[i].end];
             v.push_back(Ed[i].end);
         }
     sort(v.begin() , v.end() , cmp);
      ; i < v.size() ; i++){
         dp[now] += T[now] * siz[v[i]] + dp[v[i]];
         T[now] += T[v[i]];
     }
 }
 main(){
     N = read();
      ; i < N ; i++){
         int a = read() , b = read() , c = read();
         addEd(a , b , c);
         addEd(b , a , c);
     }
     dfs();
     cout << ) << dp[] * );
     ;
 }

CF101D Castle 树形DP、贪心的更多相关文章

  1. 【bzoj4027】[HEOI2015]兔子与樱花 树形dp+贪心

    题目描述 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它 ...

  2. [BZOJ1596] [Usaco2008 Jan]电话网络(树形DP || 贪心)

    传送门 1.树形DP #include <cstdio> #include <cstring> #include <iostream> #define N 1000 ...

  3. bzoj 3829: [Poi2014]FarmCraft 树形dp+贪心

    题意: $mhy$ 住在一棵有 $n$ 个点的树的 $1$ 号结点上,每个结点上都有一个妹子. $mhy$ 从自己家出发,去给每一个妹子都送一台电脑,每个妹子拿到电脑后就会开始安装 $zhx$ 牌杀毒 ...

  4. 树形DP+贪心(乱搞)(HDU4714)

    题意:给出一个树形图,要求把该树形成一个环最少的步骤(断开一条边和形成一条边都需一步) 分析:很明显,要想把树形成一个环,就要先把其分裂成m条子链之后把子链形成环需要的步骤是2*m+1,所以只需要m最 ...

  5. [HNOI2003]消防局的设立 树形dp // 贪心

    https://www.luogu.org/problemnew/show/P2279 一开始就想到了贪心的方法,不过一直觉得不能证明. 贪心的考虑是在深度从深到浅遍历每个结点的过程中,对于每个没有覆 ...

  6. POJ - 2057 The Lost House(树形DP+贪心)

    https://vjudge.net/problem/POJ-2057 题意 有一只蜗牛爬上某个树枝末睡着之后从树上掉下来,发现后面的"房子"却丢在了树上面,.现在这只蜗牛要求寻找 ...

  7. [POI2014]FAR-FarmCraft 树形DP + 贪心思想

    (感觉洛谷上题面那一小段中文根本看不懂啊,好多条件都没讲,直接就是安装也要一个时间啊,,,明明不止啊!还好有百度翻译......) 题意:一棵树,一开始在1号节点(root),边权都为1,每个点有点权 ...

  8. ACM学习历程—FZU2195 检查站点(树形DP || 贪心)

    Description 在山上一共有N个站点需要检查,检查员从山顶出发去各个站点进行检查,各个站点间有且仅有一条通路,检查员下山前往站点时比较轻松,而上山时却需要额外的时间,问最后检查员检查完所有站点 ...

  9. BZOJ4027/LG4107 「HEOI2015」兔子与樱花 树形DP+贪心

    问题描述 LG4107 题解 首先,我们可以直接令结点 \(x\) 的权值为 \(c[x]+son_x\) ,发现将 \(x,y\) 合并,相当于增加 \(c[x]+c[y]-1\) 的重量. 容易想 ...

随机推荐

  1. SSM环境搭建

    流程 1,maven 依赖 2,spring 配置文件 3,mybatis 配置文件 4,springMVC 配置文件 5,web.xml pom依赖 1,定义版本 <properties> ...

  2. Salesforce的Developer Console简介

    Developer Console是Salesforce提供的一个基于浏览器的集成开发环境.在Developer Console中,开发者可以新建.修改各种Apex.Visualforce.Light ...

  3. Python 解决Python安装包时提示Unable to find vcvarsall.bat的问题

    解决Python安装包时提示Unable to find vcvarsall.bat的问题   by:授客 QQ:1033553122 问题 Python安装包时,提示Unable to find v ...

  4. 安卓开发_数据存储技术_SharedPreferences类

    SharedPreferences类 供开发人员保存和获取基本数据类型的键值对. 该类主要用于基本类型,例如:booleans,ints,longs,strings.在应用程序结束后,数据仍旧会保存. ...

  5. solr-query

    解释: 1.query:获取全部数据的SQL 2.deltaImportQuery:获取增量数据时使用的SQL 3.deltaQuery:获取pk的SQL 4.parentDeltaQuery:获取父 ...

  6. oracle经验记录

    1.添加新User时必须要增加的角色权限:connect.dba.resource 2.添加表空间的语句 create tablespace DEMOSPACE datafile 'D:/test.d ...

  7. 学生与部门管理app-产品功能与界面的简单设计

    学生与部门管理app-产品功能与界面的简单设计 1. 结对成员学号 我:********* 大佬:*******10 2. 需求分析(NABCD模型) 2.1 N-需求 各个部门在开学初占据学校青春广 ...

  8. 面转栅格之ERROR 999999:执行函数时出错

    今天进行矢量面转栅格的操作时,总是出现ERROR 999999:执行函数时出错,如下图所示: 刚开始以为是栅格保存的路径太长的问题,后来发现是矢量面的路径问题,我的矢量面是放在自建的图层组下面,如下图 ...

  9. Treiber Stack介绍

    简介 Treiber Stack在 R. Kent Treiber在1986年的论文Systems Programming: Coping with Parallelism中首次出现.它是一种无锁并发 ...

  10. 转 VMware虚拟机三种联网方式(图文详细解说)

    原文地址https://blog.csdn.net/lucienduan/article/details/38233147 VMware三种网络模式联网 首先说一下VMware的几个虚拟设备 安装了V ...