[APIO2012]派遣

P1552 [APIO2012]派遣

遍历每个点,维护可并堆。

遍历结束后,将所有儿子的可并堆并起来。并计算答案。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>

using std::vector;
using std::max;
using std::swap;

const int maxn=100010;

struct Data
{
    long long sum,val;
    int ch[2];
    int dis=0;
    int tot;
    int p,f;
    void Set(int a=0,int b=0,int c=0,int d=0,int e=0,int g=0)
    {
        sum=a;val=b;
        p=c;f=d;
        tot=e;
        dis=g;
    }
};

Data H[maxn];
vector<int>V[maxn];
long long I[maxn],Cost[maxn],ans;
int n,m,root;

int Find(int x)
{
    if(H[x].f==x)   return x;
    return H[x].f=Find(H[x].f);
}

int Merge(int x,int y)
{
    if(!x||!y)  return x+y;
    if(H[x].val<H[y].val||(H[x].val==H[y].val&&x>y))    swap(x,y);
    H[x].ch[1]=Merge(H[x].ch[1],y);
    H[H[x].ch[1]].f=Find(x);
    int &Ls=H[x].ch[0],&Rs=H[x].ch[1];
    if(H[Ls].dis<H[Rs].dis) swap(Ls,Rs);
    H[x].sum=H[Ls].sum+H[Rs].sum+H[x].val;
    H[x].tot=H[Ls].tot+H[Rs].tot+1;
    H[x].dis=H[Ls].dis+1;
    return x;
}

void Pop(int now)
{
    int pas=Find(now);
    while(H[pas].sum>m)
    {
        int Ls=H[pas].ch[0],Rs=H[pas].ch[1];
        H[Ls].f=Ls;H[Rs].f=Rs;
        H[pas].Set(0,0,0,Merge(Ls,Rs));
        pas=Find(pas);
    }
    ans=max(ans,I[now]*H[pas].tot);
    return ;
}

void dfs(int now)
{
    H[now].Set(Cost[now],Cost[now],now,now,1);
    for(int i=0;i<V[now].size();i++)
    {
        dfs(V[now][i]);
        H[now].f=Merge(Find(now),Find(V[now][i]));
    }
    Pop(now);
    return ;
}

int main()
{
    H[0].dis=-1;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int a;
        scanf("%d%d%d",&a,&Cost[i],&I[i]);
        if(a==0)    root=i;
        else    V[a].push_back(i);
    }
    dfs(root);
    printf("%lld",ans);
}

posted @ 2019-01-29 00:14  Lance1ot  阅读(146)  评论(0编辑  收藏  举报