题解【Codeforces1363E】Tree Shuffling

题面

我们发现,在一个节点处进行操作等价于在它的祖先处进行操作。

于是我们就有一个想法:将每一个节点的费用改成从它到根的路径上点的费用的最小值。

然后我们发现,在深度深的节点处操作肯定比在深度浅的节点处操作更优,证明显然。

那么直接一遍 dfs,在尽量深的节点处操作,最后计算总费用输出即可。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair <int, int> PII;

inline int gi()
{
	int f = 1, x = 0; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return f * x;
}

const int INF = 0x3f3f3f3f, N = 200003, M = N << 1;

int n, m;
int a[N], b[N], c[N];
int tot, head[N], ver[M], nxt[M];
LL qz;

inline void add(int u, int v)
{
	ver[++tot] = v, nxt[tot] = head[u], head[u] = tot;
}

PII dfs(int u, int f, int mn)
{
	PII tmp = make_pair(0, 0);
	if (b[u] != c[u])
	{
		if (c[u] == 1) ++tmp.second;
		else ++tmp.first;
	}
	for (int i = head[u]; i; i = nxt[i])
	{
		int v = ver[i];
		if (v == f) continue;
		PII tmpp = dfs(v, u, min(mn, a[v]));
		tmp.first += tmpp.first, tmp.second += tmpp.second;
	}
	int need = min(tmp.second, tmp.first);
	qz += 2ll * need * mn;
	tmp.first -= need, tmp.second -= need;
	return tmp;
}

int main()
{
    int T = 1;
    while (T--)
    {
    	n = gi();
    	int to1 = 0, to0 = 0;
    	for (int i = 1; i <= n; i+=1)
    	{
    		a[i] = gi(), b[i] = gi(), c[i] = gi();
    		if (b[i] != c[i])
    		{
    			if (c[i] == 1) ++to1;
    			else ++to0;
    		}
    	}
    	for (int i = 1; i < n; i+=1)
    	{
    		int u = gi(), v = gi();
    		add(u, v), add(v, u);
    	}
    	if (to0 != to1) {puts("-1"); continue;}
    	PII ans = dfs(1, 0, a[1]);
    	if (ans.first || ans.second) puts("-1");
    	else printf("%lld
", qz);
    }
	return 0;
}
原文地址:https://www.cnblogs.com/xsl19/p/13025914.html