首页 > 其他分享 >EPIC Institute of Technology Round Summer 2024 (Div. 1 + Div. 2) E. Wonderful Tree!(树,贪心)

EPIC Institute of Technology Round Summer 2024 (Div. 1 + Div. 2) E. Wonderful Tree!(树,贪心)

时间:2024-10-22 21:19:05浏览次数:3  
标签:Summer Institute res sum cin int depth mp Div

题目链接

EPIC Institute of Technology Round Summer 2024 (Div. 1 + Div. 2) E. Wonderful Tree!

思路

题目要求令所有的 a v ≤ ∑ u ∈ s o n ( v ) a u a_{v} \le \sum_{u \in son(v)}a_{u} av​≤∑u∈son(v)​au​。我们令 b v = ∑ u ∈ s o n ( v ) a u − a v b_{v} = \sum_{u \in son(v)}a_{u} - a_{v} bv​=∑u∈son(v)​au​−av​,则问题转化为了使所有的 b v ≥ 0 b_{v} \ge 0 bv​≥0的最少操作数。

对于任意节点 v v v,对其子树中除自己的任意一个节点 u u u,使 b u = b u − 1 b_{u} = b_{u} - 1 bu​=bu​−1, b v = b v + 1 b_{v} = b_{v} + 1 bv​=bv​+1,操作的代价是 u u u到 v v v的距离。

对于每一个 b < 0 b < 0 b<0的节点,我们只要贪心的先选深度小且 b b b为正值的节点,用它的 b b b值来填充自己的。叶子节点的 b b b值设置为正无穷即可。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> pii;
const int N = 5e3 + 5, M = 1e4 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;

int n, ans;
int a[N], b[N], depth[N];
vector<int>mp[N];
void dfs1(int u, int deep)
{
	b[u] = -a[u];
	depth[u] = deep;
	for (int j : mp[u])
	{
		dfs1(j, deep + 1);
		b[u] += a[j];
	}
	if (!mp[u].size()) b[u] = inf;
}
vector<int> dfs2(int u)
{
	vector<int>res;
	for (int j : mp[u])
	{
		vector<int>v = dfs2(j);
		for (int val : v)
			res.push_back(val);
	}
	sort(res.begin(), res.end(), [&](int x, int y) {return depth[x] > depth[y];});
	if (b[u] > 0) res.push_back(u);
	else if (b[u] < 0)
	{
		int idx = res.size() - 1;
		while (b[u] < 0)
		{
			int v = res[idx];
			int sum = min(-b[u], b[v]);
			b[v] -= sum, b[u] += sum;
			ans += sum * (depth[v] - depth[u]);
			if (b[v] == 0) idx--, res.pop_back();
		}
	}
	return res;
}
void solve()
{
	cin >> n;
	ans = 0;
	for (int i = 1; i <= n; i++)
	{
		mp[i].clear();
	}
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	for (int i = 2, p; i <= n; i++)
	{
		cin >> p;
		mp[p].push_back(i);
	}
	dfs1(1, 1);
	dfs2(1);
	cout << ans << endl;
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int test = 1;
	cin >> test;
	for (int i = 1; i <= test; i++)
	{
		solve();
	}
	return 0;
}

标签:Summer,Institute,res,sum,cin,int,depth,mp,Div
From: https://blog.csdn.net/weixin_74754298/article/details/143167656

相关文章

  • Codeforces Round 980 (Div. 2) C题
    sort用法Sort(start,end,cmp)voidsort(RandomAccessIteratorfirst,RandomAccessIteratorlast,Comparecomp);参数[5](1)start表示要排序数组的起始地址;迭代器的起始位置,对于数组来说就是数组的首地址,一般写上数组名就可以,因为数组名是一个指针常量。(2)end表示数组结束地......
  • Codeforces Round 980 (Div. 2)
    A.ProfitableInterestRate题意:Alice有\(a\)元钱。银行有两种业务:业务A:存钱,但是要求最少要存\(b\)元业务B:花费x元,使得业务A中的要求\(b\)减少\(2*x\)元求Alice最多可以存多少钱分析如果Alice要存钱,要使得\((ans=a-x)\)就要大于业务A的要求\[\left\{\beg......
  • AT_agc064_c [AGC064C] Erase and Divide Game 题解
    先考虑所有\(l_i=r_i\)时怎么做,可以建出反向Trie树,问题转化为从根开始每次向左子树或右子树走,第一个拿到空子树的人输,直接在Trie上dp即可。考虑从叶子层开始对每一层的点合并两个子树的dp值,发现每一层值相同的连续段是较少的。于是可以维护这些连续段,每次合并要将每个......
  • Codeforces Round 980 (Div. 2)
    A-ProfitableInterestRatevoidsolve(){ cin>>n>>m; if(n>=m)cout<<n<<'\n'; else { intc=m-n; if(c>=n)cout<<"0\n"; elsecout<<n-c<<'\n'; } return;}B-Buyin......
  • 「题解」Codeforces Round 980 (Div. 2)
    before\(A\simD\)的题解A.ProfitableInterestRateProblemA.ProfitableInterestRateSol&Code数学题,有\(a-x\geqb-2x\),得\(x=b-a\)。特判\(a\geqb\)以及\(a<x\)的情况即可。#include<bits/stdc++.h>#defineM10001#defineN......
  • Educational Codeforces Round 165 (Rated for Div. 2) - VP记录
    A.TwoFriends一共只有两种情况:存在\(A\)的最好朋友是\(B\)且\(B\)的最好朋友是\(A\)的情况:此时只需邀请这两个人即可。不存在上述情况:设某个人\(A\)的最好朋友是\(B\),\(B\)的最好朋友是\(C\),这时邀请\(A,B,C\)三个人就可使\(A,B\)到场。根据上述两种情......
  • Codeforces Round 979 (Div. 2)
    CodeforcesRound979(Div.2)总结A首先第一位的贡献一定是\(0\),然后考虑接下来\(n-1\)位,我们可以把最大值和最小值放在第一位和第二位,这样贡献就是\((max-min)\times(n-1)\)。#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#includ......
  • 「题解」Codeforces Round 979 (Div. 2)
    before\(A\simD\)的题解A.AGiftFromOrangutanProblemA.AGiftFromOrangutanSol&Code\(c_i-b_i\)最大就是\(a\)的最大值减最小值。将\(a\)的最大值\(x\)和最小值\(y\)放到头两位即可得到答案\((x-y)(n-1)\)。#include<bits/stdc++.h>#defineM......
  • Codeforces Round 980 (Div. 2) C. Concatenation of Arrays
    题目:给定n个数组a1,a2,…,an。每个数组的长度都是2。因此,ai=[ai,1,ai,2]。你需要将这些数组连接成一个长度为2n的单一数组,以便使结果数组中的逆序数最小。注意,你不需要实际计算逆序的数量。更正式地说,你需要选择一个长度为n的排列p,使得数组b=[ap1,1,ap1,2,......
  • CF round 979 div2(D-E)
    D容易观察到需要连续一段区间。这不单点修改区间查询,然后我思维就开始往线段树飘了。。。并且我到这里就以为做完了开始想实现,实际上性质都没观察准确。。但是因为这是一个1500的题所以显然有不用线段树的解。题解是差分做的,确实差分也可以操作区间观察到“LR”一定是隔断点,那......