题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2809

思路

显然,选取需要工资最少的几个人最优。

枚举领导者的编号,问题就变成了求每个点的子树中工资k能满足多少员工了。

很容易想到使用可并堆,如果选择建立小根堆会TLE,正解是选择建立大根堆,每次从这个点的子树中踢出需要工资最大的员工,如果被一个点的子节点踢出了,那么这个节点显然不会选择他。一步一步向上合并就可以A了。

代码

#include <cstdio>
#include <algorithm>

const int maxn=100000;

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

struct node
{
  node* son[2];
  node* fa;
  int val,dist;
};

node tnode[maxn+10];
node* root[maxn+10];
int n,m,cnt,nump[maxn+10],c[maxn+10],l[maxn+10];
long long giv[maxn+10],ans;
int pre[maxn+10],now[maxn+10],son[maxn+10],tot;

inline int upd_dist(node* now)
{
  if(now->son[1]==NULL)
    {
      now->dist=0;
    }
  else
    {
      now->dist=now->son[1]->dist+1;
    }
  return 0;
}

node* merge(node* a,node* b)
{
  if(a==NULL)
    {
      return b;
    }
  if(b==NULL)
    {
      return a;
    }
  if(a->val<b->val)
    {
      std::swap(a,b);
    }
  a->son[1]=merge(a->son[1],b);
  if(a->son[1]!=NULL)
    {
      a->son[1]->fa=a;
    }
  if((a->son[0]!=NULL)&&(a->son[1]!=NULL)&&(a->son[0]->dist<a->son[1]->dist))
    {
      std::swap(a->son[0],a->son[1]);
    }
  else if((a->son[0]==NULL)&&(a->son[1]!=NULL))
    {
      a->son[0]=a->son[1];
      a->son[1]=NULL;
    }
  upd_dist(a);
  return a;
}

node* getf(node* now)
{
  if(now->fa==NULL)
    {
      return now;
    }
  return getf(now->fa);
}

inline int getmax(node* x)
{
  return getf(x)->val;
}

inline node* pop(node* x)
{
  node* f=getf(x);
  node* s=merge(f->son[0],f->son[1]);
  s->fa=NULL;
  return s;
}

inline int ins(int a,int b)
{
  pre[++tot]=now[a];
  now[a]=tot;
  son[tot]=b;
  return 0;
}

int dfs(int u)
{
  root[u]=&tnode[++cnt];
  root[u]->fa=root[u]->son[0]=root[u]->son[1]=NULL;
  root[u]->val=c[u];
  root[u]->dist=0;
  giv[u]=c[u];
  nump[u]=1;
  int j=now[u];
  while(j)
    {
      int v=son[j];
      dfs(v);
      root[u]=merge(root[u],root[v]);
      giv[u]+=giv[v];
      nump[u]+=nump[v];
      j=pre[j];
    }
  while(giv[u]>m)
    {
      giv[u]-=getmax(root[u]);
      --nump[u];
      root[u]=pop(root[u]);
    }
  ans=std::max(ans,1ll*l[u]*nump[u]);
  return 0;
}

int main()
{
  n=read();
  m=read();
  for(int i=1; i<=n; ++i)
    {
      int f=read();
      ins(f,i);
      c[i]=read();
      l[i]=read();
    }
  dfs(1);
  printf("%lld\n",ans);
  return 0;
}