UVA1205 color a tree

好神的一道题

每一步在可以被染色的点选权值最大的点是错误想法,很容易(hack)

正确性质:树中除根节点以外最大权值的点,一定会在它父亲节点后立即染色

合并这两个节点,得到节点为两个权值的平均值

假设三个点

权值(x,y,z)(x,y)连续进行操作,就有两种染色方案

先染(x,y) ,代价(x+2y+3z) 先染(z),代价(z+2z+3y)

考虑两个代价的大小关系,把两个式子都加上((z-y))再除以二

得到(1.(x+y)/2+2z) (2.z+2((x+y)/2))

所以合并两个点是正确的,

等效权值:原始点权值总和/该点包含的原始点数

struct node{int f,siz,val;}a[N];
int n,R,fa[N]; bool vis[N];
priority_queue<pair<double,int> >q;
int find(int x){return fa[x] == x ? x : fa[x] = find(fa[x]);}
int main(){
	while(~scanf("%d%d",&n,&R)){
		int ans = 0,u,v;
		for(int i = 1;i <= n;++i){
			scanf("%d",&a[i].val);
			a[i].siz = 1; ans += a[i].val;
			fa[i] = i;vis[i] = 0;
			if(i == R) continue;
			q.push(make_pair(a[i].val,i));
		}
		for(int i = 1;i < n;++i){
			scanf("%d%d",&u,&v);
			a[v].f = u;
		}
		while(!q.empty()){
			int p = q.top().second;
			q.pop();
			if(vis[p]) continue;
			vis[p] = 1;
			int f = find(a[p].f);
			ans += a[f].siz * a[p].val;
			a[f].val += a[p].val;
			a[f].siz += a[p].siz;
			if(f != R) q.push(make_pair((double)a[f].val/a[f].siz,f));
			fa[p]=f;
		}
		printf("%d
",ans);	
	}
}
原文地址:https://www.cnblogs.com/shikeyu/p/13738244.html