[可并堆学习]

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标记

bzoj2806 [Apio2012]dispatching可并堆

模板左偏树(可并堆) 可并堆_并查集

可并堆

luogu_P3377 左偏树(可并堆)

[可并堆] Bzoj P1367 sequence