用模板快速建站,中园建设银行网站,还能电子商务网站建设,免费行情软件app网站大全入口正题
题目链接:https://www.luogu.org/problemnew/show/P5290 题目大意
将一棵树的所有节点分城若干个组。每个组的价格是这个组中价格最大的点#xff0c;要求这个组中没有任何祖孙关系。 求所有组的权值和最小。(1号为根节点) 解题思路
我们先想10,11,1210,11,1210,11,12…正题
题目链接:https://www.luogu.org/problemnew/show/P5290 题目大意
将一棵树的所有节点分城若干个组。每个组的价格是这个组中价格最大的点要求这个组中没有任何祖孙关系。 求所有组的权值和最小。(1号为根节点) 解题思路
我们先想10,11,1210,11,1210,11,12的点(1号节点最多有两条支链)。
我们可以将两条链分成两个组然后每次取两个组中最大的两个进行合并。
那如果有多条支链但是这些支链不重合呢那么我们可以将前两个合并好之后继续用现在的来合并后面的因为这样一定不会重合。
那如果支链重合呢那么我们假设一个节点的所有子节点都合并好了那么我们是不是就可以用上面的方法得出这个点然后继续用来求父节点。
我们可以将每个点开一个堆然后从子节点合并给父节点。时间复杂度O(n2logn)O(n^2\ log\ n)O(n2 log n)显然无法胜任本题但我们可以每次合并的时候将小的堆合并到大的堆(启发式合并)那么时间就会被优化到O(nlog2n)O(n\ log^2\ n)O(n log2 n)(每个点最多被合并lognlog\ nlog n次) codecodecode
#includecstdio
#includequeue
#includealgorithm
#define ll long long
using namespace std;
const ll N2e510;
struct node{ll to,next;
}a[N];
ll ls[N],tot,ans,w[N],id[N],cnt,tmp[N],n;
priority_queuell d[N];
void addl(ll x,ll y)
{a[tot].toy;a[tot].nextls[x];ls[x]tot;
}
void count_ans(ll x)
{id[x]cnt;for(ll ils[x];i;ia[i].next){ll ya[i].to;count_ans(y);if(d[id[y]].size()d[id[x]].size()) swap(id[x],id[y]);ll lend[id[y]].size();for(ll i1;ilen;i){tmp[i]max(d[id[x]].top(),d[id[y]].top());d[id[x]].pop();d[id[y]].pop();}for(ll i1;ilen;i)d[id[x]].push(tmp[i]);}d[id[x]].push(w[x]);
}
int main()
{scanf(%lld,n);for(ll i1;in;i)scanf(%lld,w[i]);for(ll i2;in;i){ll x;scanf(%lld,x);addl(x,i);}count_ans(1);while(!d[id[1]].empty())ansd[id[1]].top(),d[id[1]].pop();printf(%lld,ans);
}