【CF1120D Power Tree】题解

题目链接

题目

You are given a rooted tree with n n n vertices, the root of the tree is the vertex 1 1 1 . Each vertex has some non-negative price. A leaf of the tree is a non-root vertex that has degree 1 1 1 .

Arkady and Vasily play a strange game on the tree. The game consists of three stages. On the first stage Arkady buys some non-empty set of vertices of the tree. On the second stage Vasily puts some integers into all leaves of the tree. On the third stage Arkady can perform several (possibly none) operations of the following kind: choose some vertex v v v he bought on the first stage and some integer x x x , and then add x x x to all integers in the leaves in the subtree of v v v . The integer x x x can be positive, negative of zero.

A leaf a a a is in the subtree of a vertex b b b if and only if the simple path between a a a and the root goes through b b b .

Arkady's task is to make all integers in the leaves equal to zero. What is the minimum total cost s s s he has to pay on the first stage to guarantee his own win independently of the integers Vasily puts on the second stage? Also, we ask you to find all such vertices that there is an optimal (i.e. with cost s s s ) set of vertices containing this one such that Arkady can guarantee his own win buying this set on the first stage.

给定一棵 \(n\) 个点的有根树,\(1\) 为根。定义 \(u\) 为叶子当且仅当它不是根且度数为 \(1\)

你可以选择花费 \(w_u\) 的代价控制 \(u\) 点。当一个点被控制时你可以选择给它的子树内的叶子的点权都加上一个值 \(v\) 。你需要控制若干个点,使得花费的代价尽量少,无论怎样规定叶子的初始点权,都可以通过操作你选择的点来让所有叶子的点权清空。

思路

对于每个叶子节点从左到右编号,然后就可以处理处所有点所控制叶子节点的左右区间。

要使每个节点被唯一控制,就要保证所有叶子节点都作为区间的左右端点。

于是可以根据区间建图,然后跑最小生成树。

跑最小生成树时要注意题目是输出所有可行解交集。

总结

这是一道很有意思的思维题。

这道题首先要转化模型,把树转成序列,控制范围转成区间。

又有使每个点被唯一确定,又已知区间情况,可以转化为前缀和建图。

Code

// Problem: CF1120D Power Tree
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1120D
// Memory Limit: 250 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 200010 
struct node
{
	int x, y, z, n; 
}d[N<<1], a[N<<1]; 
int n, m, i, j, k; 
int u, v, w[N]; 
int f[N], h[N]; 
int l[N], r[N]; 
int ans, cnt, num; 
priority_queue<int, vector<int>, greater<int> >q; 

void cun(int x, int y)
{
	d[++k].x=x; d[k].y=y; 
	d[k].n=h[x]; h[x]=k; 
}

void Cun(int x, int y, int z,  int o)
{
	a[++m].x=x; a[m].y=y; 
	a[m].z=z; a[m].n=o; 
}

void dfs(int x, int fa)
{
	if(!d[h[x]].n && x!=1) l[x]=r[x]=++cnt; 
	for(int g=h[x]; g; g=d[g].n)
	{
		int y=d[g].y; 
		if(y==fa) continue; 
		dfs(y, x); 
		l[x]=min(l[x], l[y]); 
		r[x]=max(r[x], r[y]); 
	}
	Cun(l[x]-1, r[x], w[x], x); 
	// printf("%lld: %lld %lld %lld\n", x, l[x], r[x], w[x]); 
}

bool cmp(node x, node y)
{
	return x.z<y.z; 
}

int fa(int x)
{
	if(f[x]==x) return x; 
	return f[x]=fa(f[x]); 
}

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	memset(l, 0x3f, sizeof(l)); 
	memset(r, 0x80, sizeof(r)); 
	n=read(); 
	for(i=1; i<=n; ++i) w[i]=read(); 
	for(i=1; i<n; ++i)
	{
		u=read(); v=read(); 
		cun(u, v); cun(v, u); 
	}
	dfs(1, 0); 
	for(i=0; i<=cnt; ++i) f[i]=i; 
	sort(a+1, a+m+1, cmp); 
	for(i=1; i<=m; ++i) 
	{
		k=i; 
		while(a[k].z==a[k+1].z && k<n) ++k; 
		for(j=i; j<=k; ++j)
		{
			u=fa(a[j].x); 
			v=fa(a[j].y); 
			// printf("%lld %lld\n", u, v); 
			if(u!=v)
			{
				++num; 
				q.push(a[j].n); 
			}
		}
		for(j=i; j<=k; ++j)
		{
			u=fa(a[j].x); 
			v=fa(a[j].y); 
			// printf("%lld %lld\n", u, v); 
			if(u!=v)
			{
				f[u]=v; 
				ans+=a[j].z; 
			}
		}
		i=k; 
	}
	printf("%lld %lld\n", ans, num); 
	while(!q.empty()) 
		printf("%lld ", q.top()), q.pop(); 
	return 0; 
}

posted @ 2022-01-24 14:13  zhangtingxi  阅读(63)  评论(0编辑  收藏  举报