[APIO2012]派遣

一、題目

點此看題

二、解法

可並堆板題,我們維護一個大根堆,每次把兒子的堆併到父親上去,然後用父親的領導力乘上最多選的個數來更新答案,容易發現如果一個堆中的元素和超過了mm,那麼直接刪去最大值,當前最大值不會用,以後更不會用,時間複雜度O(nlogn)O(n\log n)

#include <cstdio>
#include <iostream>
using namespace std;
#define ll long long
const int M = 100005;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
int n,m,ch[M][2],val[M],dis[M],rt[M],fa[M],l[M],siz[M];
ll ans,sum[M];
int merge(int x,int y)
{
    if(!x || !y) return x|y;
    if(val[x]<val[y]) swap(x,y);
    ch[x][1]=merge(ch[x][1],y);
    if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
    dis[x]=dis[ch[x][1]]+1;
    return x;
}
int main()
{
    dis[0]=-1;
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        fa[i]=read();val[i]=read();l[i]=read();
        siz[i]=1;ans=max(ans,1ll*l[i]);
        sum[i]=val[i];rt[i]=i;
    }
    for(int i=n;i>1;i--)
    {
        int f=fa[i];
        rt[f]=merge(rt[i],rt[f]);
        siz[f]+=siz[i];sum[f]+=sum[i];
        while(sum[f]>m)
        {
            sum[f]-=val[rt[f]];
            rt[f]=merge(ch[rt[f]][0],ch[rt[f]][1]);
            siz[f]--;
        }
        ans=max(ans,1ll*l[f]*siz[f]);
    }
    printf("%lld\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章