[Apio2012]dispatching 左偏树做法

http://codevs.cn/problem/1763/

 

维护子树大根堆,当子树薪水和>m时,删除最贵的点

 

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

int n,m;

#define N 100001

int lc[N],rc[N];
int key[N],dis[N];

int fa[N],siz[N],lead[N],money[N];
LL sum[N],ans;

int tot,nxt[N],to[N],front[N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
}

int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }

int merge(int a,int b)
{
    if(!a || !b) return a+b;
    if(money[a]<money[b]) swap(a,b);
    rc[a]=merge(rc[a],b);
    siz[a]=1+siz[lc[a]]+siz[rc[a]];
    sum[a]=money[a]+sum[lc[a]]+sum[rc[a]];
    if(dis[rc[a]]>dis[lc[a]]) swap(rc[a],lc[a]);
    if(!rc[a]) dis[a]=0;
    else dis[a]=dis[rc[a]]+1;
    return a;
}

void erase(int x)
{
    fa[x]=merge(lc[x],rc[x]);
    fa[fa[x]]=fa[x];
}

void dfs(int x)
{
    for(int i=front[x];i;i=nxt[i])
    {
        dfs(to[i]);
        int u=find(to[i]),v=find(x);
        int w=merge(u,v);
        fa[u]=fa[v]=w;
        fa[w]=w;
        while(sum[w]>m) erase(w),w=fa[w];
    }
    ans=max(ans,(LL)lead[x]*siz[find(x)]);
}

int main()
{
    read(n); read(m);
    int f,rt;
    for(int i=1;i<=n;++i) 
    {
        read(f);
        if(f) add(f,i);
        else rt=i;
        read(money[i]);
        read(lead[i]);
        fa[i]=i;
        siz[i]=1;
        sum[i]=money[i];
    }
    dfs(rt);
    cout<<ans;
}

 

posted @ 2018-01-04 14:42  TRTTG  阅读(229)  评论(0编辑  收藏  举报