[LOJ3052] [十二省联考 2019] 春节十二响

题目链接

LOJ:https://loj.ac/problem/3052

洛谷:https://www.luogu.org/problemnew/show/P5290

BZOJ:https://www.lydsy.com/JudgeOnline/problem.php?id=5499

Solution

部分分有一个链的情况极大的提示了正解。

考虑链情况怎么做,显然是(1)号节点向下延伸出了两条支链,那么我们可以分别( m sort)然后最大的和最大的成对,次打的同理,这样显然是最优的。

那么我们考虑二叉树怎么做,同样对于点(x)我们开一个堆记录这个点的子树的使用信息,那么点(x)可以通过两个儿子按照链情况一样的合并得到。

普通的树同理,如果我们加一个启发式合并就可以做到(O(nlog n))

注意启发式合并的时候有一个( m swap)堆的过程,这玩意在( m BZOJ)好像会发生奇怪的错误反正窝是MLE了,所以我们记个编号就好了。好像原因是因为BZOJ不支持c++11...

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

#define ll long long 

void print(ll x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('
');}

#define lf double

#define pii pair<int,int >
#define vec vector<int >

#define pb push_back
#define mp make_pair
#define fr first
#define sc second

const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;

int head[maxn],tot,n,a[maxn],sta[maxn],top,id[maxn];
struct edge{int to,nxt;}e[maxn<<1];

priority_queue<int > s[maxn];

void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}

void dfs(int x,int fa) {
    for(int v,i=head[x];i;i=e[i].nxt) {
        if((v=e[i].to)==fa) continue;top=0;dfs(v,x);
        if(s[id[v]].size()>s[id[x]].size()) swap(id[x],id[v]);
        while(s[id[v]].size()) sta[++top]=max(s[id[x]].top(),s[id[v]].top()),s[id[x]].pop(),s[id[v]].pop();
        while(top) s[id[x]].push(sta[top--]);
    }s[id[x]].push(a[x]);
}

int main() {
    read(n);for(int i=1;i<=n;i++) read(a[i]),id[i]=i; 
    for(int i=2,x;i<=n;i++) read(x),ins(i,x);
    dfs(1,0);ll ans=0;while(s[id[1]].size()) ans+=(ll)s[id[1]].top(),s[id[1]].pop();
    write(ans);
    return 0;
}
原文地址:https://www.cnblogs.com/hbyer/p/10761097.html