题干

In a village called Byteville, there are houses connected with N-1 roads. For each pair of houses, there is a unique way to get from one to another. The houses are numbered from 1 to . The house no. 1 belongs to the village administrator Byteasar. As part of enabling modern technologies for rural areas framework, computers have been delivered to Byteasar's house. Every house is to be supplied with a computer, and it is Byteasar's task to distribute them. The citizens of Byteville have already agreed to play the most recent version of FarmCraft (the game) as soon as they have their computers. Byteasar has loaded all the computers on his pickup truck and is about to set out to deliver the goods. He has just the right amount of gasoline to drive each road twice. In each house, Byteasar leaves one computer, and immediately continues on his route. In each house, as soon as house dwellers get their computer, they turn it on and install FarmCraft. The time it takes to install and set up the game very much depends on one's tech savviness, which is fortunately known for each household. After he delivers all the computers, Byteasar will come back to his house and install the game on his computer. The travel time along each road linking two houses is exactly 1 minute, and (due to citizens' eagerness to play) the time to unload a computer is negligible. Help Byteasar in determining a delivery order that allows all Byteville's citizens (including Byteasar) to start playing together as soon as possible. In other words, find an order that minimizes the time when everyone has FarmCraft installed.

INPUT

OUTPUT

The first and only line of the standard output should contain a single integer: the (minimum) number of minutes after which all citizens will be able to play FarmCraft together.

奇妙的翻译

mhy住在一棵有n个点的树的1号结点上,每个结点上都有一个妹子。

mhy从自己家出发,去给每一个妹子都送一台电脑,每个妹子拿到电脑后就会开始安装zhx牌杀毒软件,第i个妹子安装时间为。

树上的每条边mhy能且仅能走两次,每次耗费1单位时间。mhy送完所有电脑后会回自己家里然后开始装zhx牌杀毒软件。

卸货和装电脑是不需要时间的。

求所有妹子和mhy都装好zhx牌杀毒软件的最短时间。

(哪里冒出来的妹子???)

瞎想:
  • 每条边都只能走两次,而且我们最后必须回到老家,意味着我们必须一次遍历完整棵树(包括每棵子树)
  • 读完题我们要get到一个很重要的点:装软件和送电脑是可以同时进行的(妹子居然会装电脑! )
  • 我们假设一个节点有两个子节点A和B,定义 f[i] 为遍历完子树后再回到 i 点的最短用时,siz[i] 为 i 的子树的总大小,那么,我们可以得到:
  • 先去遍历A的子树,总时间:siz[A]*2 + f[B] ;//当然这里其实是要+1的,因为我们从A或B到 i 还需要再走一步,看我下面代码可以知道,这里不影响
  • 先去遍历B的子树,总时间:siz[B]*2 + f[A] ;
  • 我们用结构体记录下所有子树的( f[i] , siz[i]*2)
  • 按照 time +p.siz < p.time + siz 从小到大排序
  • 理由:如果先遍历A更合适,有 siz[A]2+f[B] < siz[B]2+f[A]; //这里之前脑子一抽写反了,希望没误导大家...
  • 这里我觉得解释一下比较好,相比较而言,我们肯定更愿意先去安装软件耗时更多而跑图用时更少的子树,因为这样我们就可以让他们在我们给别的地方送电脑的时候自行安装,从而节省时间。那么在这里,我们假设f[A]和f[B]相等,那么此时siz[B]肯定是大于siz[A]的,这意味这A和B的总用时相等,但我们遍历B时耽搁在路上的时间更多(子树规模更大嘛),所以相比较而言A的装软件用时更长,也就是我们应该先走A;
  • 最后的答案 f[x]=max(w[x],f[v]+sum)

这里我们结合代码分析一下:

struct node{
int time,siz;
bool operator <(const node& p)const{
return p.time+siz<time+p.siz;
}
}t[maxn];
void dfs(int u,int fa){
siz[u]=1;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
}
int tot=0;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==fa) continue;
tot++;//儿子数量
t[tot].time=f[v]+1;//从v回到u需加1
t[tot].siz=siz[v]*2;//这里乘2,下面计算时就不用乘2了,减少失误
}
sort(t+1,t+1+tot);
int sum=0,maxx=(siz[u]-1)*2;//sum依然是目前跑路所需总时间,maxx初始为单纯跑完u的子树所需总时间
for(int i=1;i<=tot;i++){
maxx=max(maxx,t[i].time+sum);//更新目前最大用时
sum+=t[i].siz;//累加跑路时间
}
f[u]=max(w[u],maxx);//如果单单u点装软件用时比完全弄完所有子树都费事,直接取w[u]
}

完整代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=5*1e6+10;
int n,f[maxn],head[maxn],len=0,siz[maxn];
int w[maxn];
struct Edge{
int next,to;
}edge[maxn<<1];
void Add(int u,int v){
edge[++len].next=head[u];
edge[len].to=v;
head[u]=len;
}
struct node{
int time,siz;
bool operator <(const node& p)const{
return p.time+siz<time+p.siz;
}
}t[maxn];
void dfs(int u,int fa){
siz[u]=1;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
}
int tot=0;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==fa) continue;
tot++;
t[tot].time=f[v]+1;
t[tot].siz=siz[v]*2;
}
sort(t+1,t+1+tot);
for(int i=1;i<=tot;i++)
printf("%d %d\n",t[i].time,t[i].siz);
int sum=0,maxx=(siz[u]-1)*2;
for(int i=1;i<=tot;i++){
maxx=max(maxx,t[i].time+sum);
sum+=t[i].siz;
}
f[u]=max(w[u],maxx);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
Add(u,v),Add(v,u);
}
dfs(1,0);
int ans=0;
ans=max(f[1],w[1]+(n-1)*2);
cout<<ans<<endl;
return 0;
}

[POI2014]FAR-FarmCraft (树规+贪心)的更多相关文章

  1. [HEOI2015]兔子与樱花 树规+贪心

    鬼能想到是个贪心.明明觉得是树规啊..又完美爆零.. 从叶子节点往上更新,能保证最优解(这块想了半天). 证明:当你的子树上有能删的点而你不删时,可能会对子树的根节点有利,最好的情况是使子树根节点由不 ...

  2. [Poi2014]FarmCraft 树状dp

    对于每个点,处理出走完其子树所需要的时间和其子树完全下载完软件的时间 易证,对于每个点的所有子节点,一定优先选择差值大的来给后面的时间 树规+贪心. #include<cstdio> #i ...

  3. Codeforces Gym 100231B Intervals 线段树+二分+贪心

    Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...

  4. BZOJ_3524_[Poi2014]Couriers_主席树

    BZOJ_3524_[Poi2014]Couriers_主席树 题意:给一个长度为n的序列a.1≤a[i]≤n. m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r- ...

  5. 【BZOJ5495】[十二省联考2019]异或粽子(主席树,贪心)

    [BZOJ5495][十二省联考2019]异或粽子(主席树,贪心) 题面 BZOJ 洛谷 题解 这不是送分题吗... 转异或前缀和,构建可持久化\(Trie\). 然后拿一个堆维护每次的最大值,每次如 ...

  6. 【arc073e】Ball Coloring(线段树,贪心)

    [arc073e]Ball Coloring(线段树,贪心) 题面 AtCoder 洛谷 题解 大型翻车现场,菊队完美压中男神的模拟题 首先钦定全局最小值为红色,剩下的袋子按照其中较大值排序. 枚举前 ...

  7. 【9.2校内测试】【开学祭】【exgcd】【树规(背包】【模拟】

    比较裸的$exgcd$的应用? $exgcd$可以算出在$x$和$y$分别是最小正整数时的解.注意在这里因为有$a(x+\frac{b}{d})+b(y-\frac{a}{d})=c$,$d=gcd( ...

  8. 【agc028E】High Elements(动态规划,线段树,贪心)

    [agc028E]High Elements(动态规划,线段树,贪心) 题面 AtCoder 你有一个\([1,N]\)的排列\(P\). 一个长度为\(N\)的字符串\(S\)是好的,当且仅当: 两 ...

  9. BZOJ3829[Poi2014]FarmCraft——树形DP+贪心

    题目描述 In a village called Byteville, there are   houses connected with N-1 roads. For each pair of ho ...

随机推荐

  1. neo4j导入csv文件

    neo4j导入csv文件 关于neo4j的安装 官网和网上博客提供了n中安装的方法,这里不再赘述: 普通安装: https://cloud.tencent.com/developer/article/ ...

  2. local 对象补充

    昨日回顾 1 @app.before_first_request,再项目启动后接收到的第一个请求,会执行before_first_request,他再@app.before_request之前执行.他 ...

  3. 使用Docker搭建Nextcloud SSL站点

    1.启动mariadb docker run -d \ --name mysql \ -e MYSQL_ROOT_PASSWORD=<你的mysql密码> \ -p 13306:3306 ...

  4. 基于移动最小二乘法的点云曲面拟合(python)

    1.移动最小二乘法介绍 为了更好地对数据量大且形状复杂的离散数据进行拟合,曾清红等人[1]开发出一种新的算法——移动最小二乘法.这种新的最小二乘算法为点云数据的处理提供了新的方法.使用点云数据拟合曲面 ...

  5. 使用Java代码配置MyBatis Generator

    使用MyBatis Generator生成器时,有时候没办法使用xml型的配置文件,比如将Maven项目设置成pom打包方式(<packaging>pom</packaging> ...

  6. Selenium上传文件方法大全

    最好的方法:调js 其他方法: Python pywin32库,识别对话框句柄,进而操作 SendKeys库 autoIT,借助外力,我们去调用其生成的au3或exe文件. keybd_event,跟 ...

  7. matlab中imwrite函数详解(imwrite的输出格式)

    参考资料: https://www.mathworks.com/help/matlab/ref/imwrite.html?s_tid=srchtitle 你可能觉得imread函数很简单,但是还是有一 ...

  8. C# WPF - MVVM实现OPC Client管理系统

    前言 本文主要讲解采用WPF MVVM模式设计OPC Client的过程,算作对于WPF MVVM架构的学习记录吧!不足之处请不吝赐教,感谢! 涉及知识点 C#基础 Xaml基础 命令.通知和数据绑定 ...

  9. Ubuntu下安装PIL

    Ubuntu下安装PIL 1)sudo apt-get install libjpeg-dev 2)sudo apt-get install libfreetype6-dev 3)sudo easy_ ...

  10. react 使用的方法:

    react  使用方法: 第一步: 初始化react 项目 (1)安装node npm (2)npm install --global create-react-app (3)create-react ...