bzoj2809 [Apio2012]dispatching

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

其实可以按照树的形状暴力枚举把谁当做管理者!

  考虑到收益只和忍者个数有关,所以当薪水超限时把薪水最高的忍者去掉就行了。

    这是一个大根堆。于是变成可并堆,用了左偏树。

第一次的左偏树。感觉写起来意外地简单。(虽然并不是1A)

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,head[N],c[N][2],dis[N],tot,rt[N],cnt[N],mas;
ll lm,v[N],w[N],ans,sum[N],val[N];
struct Edge{
    int next,to;
    Edge(int n=0,int t=0):next(n),to(t) {}
}edge[N];
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch<='9'&&ch>='0')(ret*=10)+=ch-'0',ch=getchar();
    return ret;
}
ll rdl()
{
    ll ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch<='9'&&ch>='0')(ret*=10)+=ch-'0',ch=getchar();
    return ret;
}
int merge(int x,int y)
{
    if(!x)return y;if(!y)return x;
    if(val[x]<val[y])swap(x,y);
    c[x][1]=merge(c[x][1],y);
    if(dis[c[x][1]]>dis[c[x][0]])swap(c[x][1],c[x][0]);
    if(c[x][1])dis[x]=dis[c[x][1]]+1;
    sum[x]=sum[c[x][0]]+sum[c[x][1]]+val[x];//+val[x]
    cnt[x]=cnt[c[x][0]]+cnt[c[x][1]]+1;//+1
    return x;
}
void dfs(int cr,int f)
{
    rt[cr]=++tot;sum[tot]=val[tot]=v[cr];cnt[tot]=1;
    for(int i=head[cr],v;i;i=edge[i].next)
        if((v=edge[i].to)!=f)
        {
            dfs(v,cr);rt[cr]=merge(rt[cr],rt[v]);
        }
    while(sum[rt[cr]]>lm)rt[cr]=merge(c[rt[cr]][1],c[rt[cr]][0]);
    ans=max(ans,cnt[rt[cr]]*w[cr]);
}
int main()
{
    n=rdn();lm=rdl();
    for(int i=1;i<=n;i++)
    {
        int tp=rdn();edge[i]=Edge(head[tp],i);head[tp]=i;
        if(!tp)mas=i;
        v[i]=rdl();w[i]=rdl();
    }
    dfs(mas,0);//mas不一定是1 
    printf("%lld",ans);
    return 0;
}

 

posted on 2018-06-15 08:45  Narh  阅读(117)  评论(0编辑  收藏  举报

导航