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\n",ans);	
	}
}
posted @ 2020-09-27 11:01  INFP  阅读(99)  评论(0编辑  收藏  举报