[FJOI2018] 领导集团问题

题目传送门:[FJOI2018]领导集团问题


Statement:


Solution:

考虑一个DP,记\(f(i,j)\)表示子树\(i\)中选择的最小数是\(j\)的最大点数,转移比较显然。

可以发现这个可以用线段树合并优化,时间复杂度为\(\mathcal O(N\log_2N)\)

然而这题有个偷懒的启发式合并做法,考虑一个贪心。

维护每个节点的最优选择,合并的时候考虑加人根节点是否会影响超过\(2\)个节点,若没有那么加人。

时间复杂度为\(\mathcal O(N\log_2^2N)\)

code

#include <bits/stdc++.h>

const int MAXN = 2.1E5;
std::multiset <int> D[MAXN];
std::vector <int> adj[MAXN];
int Root[MAXN];
int A[MAXN];
int n;

inline void Merge(int u, int v) {
	if (D[Root[u]].size() < D[Root[v]].size())
		std::swap(Root[u], Root[v]);
	u = Root[u], v = Root[v];
	for (auto x : D[v])
		D[u].insert(x);
}

void getAns(int u) {
	for (int v : adj[u])
		getAns(v), Merge(u, v);
	auto x = D[Root[u]].lower_bound(A[u]);
	if (x != D[Root[u]].begin())
		D[Root[u]].erase(--x);
}

int main(void) {
	std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
	
	std::cin >> n;
	for (int i = 1, x; i <= n; ++i)
		std::cin >> x, D[Root[i] = i].insert(A[i] = x);
	for (int i = 2, v; i <= n; ++i)
		std::cin >> v,
		adj[v].push_back(i);
	getAns(1);
	std::cout << D[Root[1]].size() << '\n';
	return 0;
}
posted @ 2021-08-19 07:45  Beginner2670  阅读(49)  评论(0)    收藏  举报