[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;
}

浙公网安备 33010602011771号