[可并堆学习]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[可并堆学习]相关的知识,希望对你有一定的参考价值。
happy children‘s day!
【bzoj2809】【APIO2012】dispatching
dispatch:派遣,调度,快速处理的意思
题意可以简化为,找max{L[u]*可取的子数结点最大值},并且使所取结点薪水和小于M,即取最小几项。
n为10w,暴力显然会T。
考虑到递归的过程中,较大的子节点不被取,以后更加不会取,所以只需将较大的子节点弹出栈即可。
关于可并堆的写法,记录它的左节点与右结点,在这道题里,是小的并到大处,千万别忘了将他们左右结点再调换一下。
#include<cstdio> #define N 200000 #define ll long long #include<algorithm> using namespace std; ll now=0,ans=0,l[N]; int edgenum,top,n,m; int vet[N],size[N],root[N],le[N],rr[N],head[N],next[N],a[N],c[N]; ll sum[N]; void add(int u,int v) { edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum; } /*int push_up() { int k=top; while(k/2>0&&a[k]>a[k/2]) { int t=a[k];a[k]=a[k/2];a[k/2]=t;k=k/2; } } int push_down() { int k=1; while(k*2<=top) { if(k*2+1<=top&&a[k]<a[k*2+1]&&a[k*2+1]>a[k*2]) { int t=a[k];a[k]=a[k*2+1];a[k*2+1]=t;k=k*2+1; }else if(a[k]<a[k*2]) { int t=a[k];a[k]=a[k*2];a[k*2]=t;k=k*2; }else break; } }*/ int merge(int x,int y) { if(x==0||y==0)return x+y;if(c[x]<c[y])swap(x,y); rr[x]=merge(rr[x],y);swap(le[x],rr[x]);return x; } void dfs(int u) { int e=head[u];size[u]=1;sum[u]=c[u];root[u]=u; while(e>0) { int v=vet[e]; dfs(v);sum[u]+=sum[v];size[u]+=size[v]; root[u]=merge(root[u],root[v]); e=next[e]; } while(sum[u]>m){ sum[u]-=c[root[u]];size[u]--;root[u]=merge(le[root[u]],rr[root[u]]); } if(size[u]*l[u]>ans)ans=size[u]*l[u]; } int main() { scanf("%d%d",&n,&m);int x; for(int i=1;i<=n;i++) { scanf("%d%d%lld",&x,&c[i],&l[i]); add(x,i); } dfs(1);printf("%lld",ans); }
以上是关于[可并堆学习]的主要内容,如果未能解决你的问题,请参考以下文章
bzoj2333 [SCOI2011]棘手的操作 可并堆+lazy标记