【CF1120D】Power Tree 题解

原题

题意:

给定一棵有根树,每个节点有一个权值。可以选择一些节点,选出的节点可以支配它子树中的一个叶节点。要求选出一个权值和最小的节点集合,使所有的叶节点都能被支配。输出最小权值和与所有可以被选出的节点

题解:

对于第一个问题,有一个很明显的树形DP做法,然后我就被第二问输出方案搞死了。所以这里就不提了。
因为对选出的节点进行的操作仅限于它的子树中,所以我们自然的想到dfs序。对于一个节点i,设其子树所代表的dfs序为\((l,r)\)。由于每个叶节点最后的权值为0,所以其差分数组也均为0.所以我们从l向r+1连一条边,在建出的图上跑最小生成树即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define dg() printf("114514\n")
LL read() {
	LL s=0,w=1; char ch=getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w=-1; ch=getchar();}
	while(ch <= '9' && ch >= '0') s=s*10+ch-'0',ch=getchar();
	return s*w; 
}
const int N=4e5+4;  
struct tree{
	int t,nex;
} t[N]; int head[N],tot;
void add(int x,int y) {
	t[++tot].t=y; t[tot].nex=head[x]; head[x]=tot;
}
int n,c[N],l[N],r[N];
void dfs(int x,int fath) {
	bool TT=true;
	for(int i=head[x];i;i=t[i].nex) {
		int y=t[i].t;
		if(y == fath) continue;
		dfs(y,x);
		l[x]=min(l[x],l[y]); 
		r[x]=max(r[x],r[y]); 
		TT=false;
	}
	if(TT) {
		l[x] = r[x] =++tot;
	}
	return;
} 
struct Edge{
	int x,y,v,id;
} e[N];
bool cmp(Edge a,Edge b){ if(a.v == b.v) return a.id < b.id; return a.v < b.v; }  
int f[N];
int find(int x) {
	return x == f[x]?x:f[x]=find(f[x]);
}
void merge(int x,int y) { f[find(x)]=find(y); }
LL sum;
int ans[N],js; 
void solve() { 
	sort(e+1,e+n+1,cmp);
	for(int i=1;i<=n;i++) f[i]=i;
	
	for(int i=1;i<=n;) { 
	   // printf("%d ",i);
	    for(int j=i;;j++) {
	    	if(e[i].v != e[j].v) break;
	    	int tx=e[j].x,ty=e[j].y;
	    	if(find(tx) == find(ty)) continue;
	    	ans[++js]=e[j].id; 
		} 
		for(int j=i;;j++) {
			if(e[i].v != e[j].v) { i=j; break; }
			int tx=e[j].x,ty=e[j].y;
			if(find(tx) != find(ty)) {
				sum+=e[j].v; merge(tx,ty);
			}
		}
	} 
	sort(ans+1,ans+js+1);
	printf("%lld %d\n",sum,js); 
	for(int i=1;i<=js;i++) printf("%d ",ans[i]); 
	printf("\n"); return; 
} 
int main() { 
	n=read(); 
	for(int i=1;i<=n;i++) c[i]=read();
	for(int i=1;i<n;i++) {
		int x=read(),y=read();
		add(x,y); add(y,x);
	}
	tot=0;
	memset(l,0x3f,sizeof(l));
	dfs(1,0);
	tot=0;
	for(int i=1;i<=n;i++) { 
		e[i].x=l[i]; e[i].y=r[i]+1; e[i].v=c[i]; e[i].id=i;
	} 
	e[n+1].v=-1;
	solve();
	return 0;
}
/*
*/
posted @ 2021-11-15 21:44  残碑小筑  阅读(135)  评论(0)    收藏  举报
faults = { minSize : 10, maxSize : 20, newOn : 1000, flakeColor : "#FFFFFF" /* 此处可以定义雪花颜色,若要白色可以改为#FFFFFF */ }, options = $.extend({}, defaults, options); var interval= setInterval( function(){ var startPositionLeft = Math.random() * documentWidth - 100, startOpacity = 0.5 + Math.random(), sizeFlake = options.minSize + Math.random() * options.maxSize, endPositionTop = documentHeight - 200, endPositionLeft = startPositionLeft - 500 + Math.random() * 500, durationFall = documentHeight * 10 + Math.random() * 5000; $flake.clone().appendTo('body').css({ left: startPositionLeft, opacity: startOpacity, 'font-size': sizeFlake, color: options.flakeColor }).animate({ top: endPositionTop, left: endPositionLeft, opacity: 0.2 },durationFall,'linear',function(){ $(this).remove() }); }, options.newOn); }; })(jQuery); $(function(){ $.fn.snow({ minSize: 5, /* 定义雪花最小尺寸 */ maxSize: 80,/* 定义雪花最大尺寸 */ newOn: 200 /* 定义密集程度,数字越小越密集 */ }); });