bzoj4919: 大根堆
2017-07-05 18:34
411 查看
Description
给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点。每个点有一个权值v_i。你需要将这棵树转化成一个大根堆。确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i,j,如果i在树上是j的祖先,那么v_i>v_j。
请计算可选的最多的点数,注意这些点不必形成这棵树的一个连通子树。
Input
第一行包含一个正整数n(1<=n<=200000),表示节点的个数。接下来n行,每行两个整数v_i,p_i(0<=v_i<=10^9,1<=p_i<i,p_1=0),表示每个节点的权值与父亲。
Output
输出一行一个正整数,即最多的点数。平衡树启发式合并,维护当前子树内选k个点,选出的点权最大值的最小值
#include<bits/stdc++.h> const int N=200007; char buf[70007],*ptr=buf+70000; int G(){ if(ptr-buf==70000)fread(ptr=buf,1,70000,stdin); return *ptr++; } int _(){ int x=0; if(ptr-buf<69900){ while(*ptr<48)++ptr; while(*ptr>47)x=x*10+*ptr++-48; }else{ int c=G(); while(c<48)c=G(); while(c>47)x=x*10+c-48,c=G(); } return x; } int n; int v ,fa ,q ,ql=0,qr=0,deg ; std::multiset<int>vs ; typedef std::multiset<int>::iterator mit; int main(){ n=_(); for(int i=1;i<=n;++i){ v[i]=_(); ++deg[fa[i]=_()]; } for(int i=1;i<=n;++i)if(!deg[i])q[++qr]=i; while(ql!=qr){ int w=q[++ql],f=fa[w]; mit u=vs[w].lower_bound(v[w]); if(u==vs[w].end())vs[w].insert(v[w]); else *const_cast<int*>(&*u)=v[w]; if(f){ if(vs[f].size()<vs[w].size())std::swap(vs[f],vs[w]); for(mit it=vs[w].begin(),e=vs[w].end();it!=e;++it)vs[f].insert(*it); vs[w].clear(); if(!--deg[f])q[++qr]=f; } } printf("%d\n",vs[1].size()); return 0; }
相关文章推荐
- bzoj4919 [Lydsy1706月赛]大根堆
- BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)
- [BZOJ4919]大根堆 启发式合并+线段树/multiset
- [BZOJ4919][Lydsy六月份月赛 .C][树上DP][启发式合并]大根堆
- [BZOJ4919][Lydsy1706月赛]大根堆
- BZOJ 4919 大根堆(LIS)
- [bzoj4919]大根堆——set启发式合并
- 【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并
- bzoj4919 大根堆 [启发式合并]
- [bzoj4919][Lydsy1706月赛]大根堆【dp】【启发式合并】【stl】
- BZOJ 4919 大根堆
- BZOJ4919 [Lydsy1706月赛]大根堆 【dp + 启发式合并】
- bzoj 4919: [Lydsy六月月赛]大根堆
- bzoj4919 大根堆(线段树合并)
- [bzoj4919]大根堆
- [BZOJ 4919]大根堆
- 4919: [Lydsy1706月赛]大根堆 multiset 启发式合并 思路
- [JSOI2007]建筑抢修 BZOJ1029 BSOJ2228 CODEVS2913 贪心+大根堆
- 【BZOJ】【P3339&P3585】【Rmq Problem/mex】【题解】【离线】
- 【BZOJ】【3611】【HEOI2014】大工程