考试的时候,本来想拿60的贪心,但是只拿了15……很不开心!
不过现在知道正解了qwq……
对于每个点,都开一个优先队列,这个优先队列里的值,代表这个点的子树分成的若干个集合中最大的值。
那么我们对于一个没有处理的点,分别枚举每一个子树,分别合并每一个优先队列,最后再加入这个点,得到新的优先队列。
对于正确性,由于每一个点都会单独加入优先队列,所以这个点和子树中的任何一个点都不是同一集合,满足了题意,并且每一层的合并肯定是最优,大的和大的合并。
对于时间,由于每一个点都会被进行上述操作,所以 n * ,对于枚举每个儿子的优先队列,视为 logn ,删除 logn ,所以复杂度O(n * log2n)。
考试没想出来……呜呜呜
#include<cstdio> #include<iostream> #include<queue> #define MogeKo qwq #define ll long long using namespace std; const int maxn = 2e5+10; int n,f,cnt; ll w[maxn],tem[maxn],id[maxn]; ll ans; int head[maxn],to[maxn],nxt[maxn]; priority_queue <ll> q[maxn]; void add(int x,int y) { to[++cnt] = y; nxt[cnt] = head[x]; head[x] = cnt; } void dfs(int u) { id[u] = u; for(int i = head[u]; i; i = nxt[i]) { int v = to[i]; dfs(v); if(i == head[u]) { id[u] = id[v]; continue; } if(q[id[v]].size() > q[id[u]].size()) swap(id[u],id[v]); int cnt = 0; while(!q[id[v]].empty()) { tem[++cnt] = max(q[id[u]].top(),q[id[v]].top()); q[id[u]].pop(); q[id[v]].pop(); } for(int i = 1; i <= cnt; i++) q[id[u]].push(tem[i]); } q[id[u]].push(w[u]); } int main() { scanf("%d",&n); for(int i = 1; i <= n; i++) scanf("%lld",&w[i]); for(int i = 1; i <= n-1; i++) { scanf("%d",&f); add(f,i+1); } dfs(1); while(!q[id[1]].empty()) { ans += q[id[1]].top(); q[id[1]].pop(); } printf("%lld",ans); return 0; }