码迷,mamicode.com
首页 > 其他好文 > 详细

[可并堆学习]

时间:2016-06-01 21:13:11      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:

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);
}

 

[可并堆学习]

标签:

原文地址:http://www.cnblogs.com/wxxlouisa/p/5550992.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!