做完之后真的有一种 艹这么简单的题为什么我考场上没想出来 的感觉
当时在考场上已经被两个计数题的dp洗脑了,于是对着这道题推了半天的dp,最后写了个奇怪的记忆化搜索+一条链。然而写一条链的时候可能也只有我这种菜逼没看见题目里说1不一定是链的端点了。。。最后就只拿了45分
我要是能花时间好好想想一条链怎么做,这题就切了。因为一条链的情况实在是离正解很近很近。
一条链的做法:1号点至多两个分支,给每个分支开个堆,每次从两个堆里各弹一个值出来,取大的那个加入答案即可。
那么显然这个做法可以扩展到树上:给每个节点都开个堆,dfs的时候合并子树的堆即可。好像有大佬写左偏树写挂了,事实上这题只要启发式合并就行了。
于是代码真的是非常短
#include <cctype>
#include <cstdio>
#include <climits>
#include <algorithm>
#include <queue>
template <typename T> inline void read(T& x) {
int f = 0, c = getchar(); x = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
if (f) x = -x;
}
template <typename T, typename... Args>
inline void read(T& x, Args&... args) {
read(x); read(args...);
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
template <typename T> inline void writeln(T x) { write(x); puts(""); }
template <typename T> inline bool chkmin(T& x, const T& y) { return y < x ? (x = y, true) : false; }
template <typename T> inline bool chkmax(T& x, const T& y) { return x < y ? (x = y, true) : false; }
typedef long long LL;
const int maxn = 2e5 + 207;
int v[maxn], head[maxn], next[maxn], a[maxn], tot;
std::priority_queue<int> heap[maxn];
int tmp[maxn];
int n;
inline void ae(int x, int y) {
v[++tot] = y; next[tot] = head[x]; head[x] = tot;
}
void dfs(int x) {
for (int i = head[x]; i; i = next[i]) {
dfs(v[i]);
if (heap[x].size() < heap[v[i]].size()) std::swap(heap[x], heap[v[i]]);
while (!heap[v[i]].empty()) {
tmp[++tmp[0]] = std::max(heap[x].top(), heap[v[i]].top());
heap[x].pop(); heap[v[i]].pop();
}
while (tmp[0]) heap[x].push(tmp[tmp[0]--]);
}
heap[x].push(a[x]);
}
int main() {
read(n);
for (int i = 1; i <= n; ++i) read(a[i]);
for (int i = 2, f; i <= n; ++i) read(f), ae(f, i);
dfs(1);
LL ans = 0;
while (!heap[1].empty()) ans += heap[1].top(), heap[1].pop();
writeln(ans);
return 0;
}