$poj$

$Description$

一颗树有 $n$ 个节点,这些节点被标号为:$1,2,3…n,$每个节点 $i$ 都有一个权值 $A[i]$。

现在要把这棵树的节点全部染色,染色的规则是:

根节点R可以随时被染色;对于其他节点,在被染色之前它的父亲节点必须已经染上了色.

每次染色的代价为$T*A[i]$,其中$T$代表当前是第几次染色.

求把这棵树染色的最小总代价。

$Sol$

贪心:树中权值最大的点,一定会在它的父结点染色后立即染色

可以这样想,假设没有树的约束,只是一个序列,那么显然是按照从大到小排序的顺序染色为最优,现在有树的约束条件,也应该让权值最大的尽量早地染色.

因为权值最大的点与它的父结点的染色是接连进行的,所以我们可以把它们合并起来.

现在有权值为$x,y,z$的三个点,已知$x$和$y$的染色是接连着进行的,其中$x$是$y$的父结点.那么有两种决策.

1.先染$x,y$,再染$z$ ,$x+2y+3z=y+(x+y)+3z$

2.先染$z$,再染$x,y, z+2x+3y=z+y+2*(x+y)$

发现无论是上面的哪种情况有一种做法是通用的:先把$y$累加进答案,然后把$y$结点与$x$结点合并,具体来说,$x$的权值改为$(x+y)/2$,删除$y$结点.为什么是把权值改成$(x+y)/2$呢?

有一个十分重要的问题,就是如何判断这两种做法的优劣.设合并后的结点为$i$,这个结点所包含的结点数(它自己和合并进去的)为$s[i]$,包含的所有的权值和为$a[i]$.

1.$a[i]+(s[i]+1)*z.$

2.$z+a[i]*2.$

发现应该把$1$式中的$z$的系数变成$2$,把两个式子同时加上$(s[i]-1)*z$,再同除$s[i]$,变成

1.$a[i]/s[i]+2*z$

2.$z+a[i]/s[i]$

可以看成权值为$a[i]/s[i]$的结点和$z$的两个结点,根据最开始所说的贪心可知比较它们的大小就能决定先给谁染色了,于是问题就解决了.

还是要强调的是上面所赋予的新权值只能用于与别的结点比较大小从而决定染色顺序,至于答案的累加,就在对于最初始的两个式子的分析中"把$y$累加进答案"这句话.具体来说$j$结点累加进$i$结点,$ans+=a[j]*s[i]$.

$Code$

#include<iostream>
#include<cstdio>
#define il inline
#define Rg register
#define go(i,a,b) for(Rg int i=a;i<=b;i++)
#define yes(i,a,b) for(Rg int i=a;i>=b;i++)
#define db double
#define ll long long
using namespace std;
il int read()
{
int x=,y=;char c=getchar();
while(c<''||c>''){if(c=='-')y=-;c=getchar();}
while(c>=''&&c<=''){x=(x<<)+(x<<)+c-'';c=getchar();}
return x*y;
}
int n,rt,a[],fa[],s[];
ll as;
int main()
{
//while(1)
{
n=read(),rt=read();as=;
if(!n && !rt)return ;
go(i,,n)a[i]=read(),s[i]=;
go(i,,n-){int x=read(),y=read();fa[y]=x;}
go(T,,n-)
{
db maxs=;int pos;
go(i,,n)
if(i!=rt && 1.0*a[i]/s[i]>=maxs)maxs=1.0*a[i]/s[i],pos=i;
go(i,,n)
if(fa[i]==pos)fa[i]=fa[pos];
as+=a[pos]*s[fa[pos]];
s[fa[pos]]+=s[pos];
a[fa[pos]]+=a[pos];
a[pos]=;
}
as+=a[rt];
printf("%lld\n",as);
}
return ;
}

随机推荐

  1. hdu 4629 Burning (扫描线)

    Problem - 4629 以前写过PSLG模拟的版本,今天写了一下扫描线做这题. 其实这题可以用set存线段来做,类似于判断直线交的做法.不过实现起来有点麻烦,于是我就直接暴力求交点了. 代码如下 ...

  2. HDFS概念名称节点和数据节点-名称节点-文件系统元数据的持久状态

  3. SDUT-2133_数据结构实验之栈与队列三:后缀式求值

    数据结构实验之栈与队列三:后缀式求值 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 对于一个基于二元运算符的后缀表示式 ...

  4. css white-space属性

    css white-space属性 规定段落中的文本不进行换行

  5. day6_python序列化之 json & pickle & shelve 模块

    一.json & pickle & shelve 模块 json,用于字符串 和 python数据类型间进行转换pickle,用于python特有的类型 和 python的数据类型间进 ...

  6. video 获取第一帧的图片作为封面

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  7. H3C DCC的特点

  8. Activity学习(一):生命周期

    一. 认识Activity Activity是Android的四大组件之一,那么它是什么呢?如果简单的理解,可以把它当成应用的一个显示的屏幕. Activity类处于android.app包中,继承体 ...

  9. 如何检查linux是否安装了php

    方法一.在终端通过php -v命令来查看一下当前php的版本.如果没有安装php,一般会提示没有php这个命令的. 2 方法二.在终端查询安装的包中是否有php,以redhat为例,则可以执行如下命令 ...

  10. PHP会员找回密码功能的简单实现

    文章来自:博客 http://www.jb51.net/article/91944.htm 设置思路 1.用户注册时需要提供一个E-MAIL邮箱,目的就是用该邮箱找回密码. 2.当用户忘记密码或用户名 ...