【洛谷P5290】【十二省联考2019】春节十二响(贪心+启发式合并)
首先可以显然的发现段数一定是最长链的长度
手玩一下样例
似乎可以贪心,每次把最大的一个个丢?
事实证明这是对的
这样就有了
再把链写了就可以拿到的好成绩
考虑100分,如果合并2条子树的链
由排序不等式可以证明第2边第大的数放一起是最有的
那就可以利用优先队列启发式合并做
看起来复杂度是的
但实际上考虑我们只会将小的那一个堆和大的比较,而且只取值大的
实际上每个点只会被一次
所以复杂度其实是的
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return res*f;
}
const int N=200005;
int siz[N],rt[N],val[N],n;
int adj[N],nxt[N],to[N],cnt,fa[N],stk[N],top;
ll ans;
priority_queue<int> q[N];
inline void addedge(int u,int v){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
void dfs(int u){
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
dfs(v);
if(q[rt[v]].size()>q[rt[u]].size())swap(rt[u],rt[v]);
while(q[rt[v]].size())stk[++top]=max(q[rt[u]].top(),q[rt[v]].top()),q[rt[u]].pop(),q[rt[v]].pop();
while(top)q[rt[u]].push(stk[top--]);
}
q[rt[u]].push(val[u]);
}
int main(){
n=read();
for(int i=1;i<=n;i++)rt[i]=i,val[i]=read();
for(int i=2;i<=n;i++){
fa[i]=read(),addedge(fa[i],i);
}
dfs(1);
while(q[rt[1]].size())ans+=q[rt[1]].top(),q[rt[1]].pop();
cout<<ans;
}