bzoj2809 [Apio2012]dispatching

来源:互联网 发布:网络推广部 编辑:程序博客网 时间:2024/05/18 02:41

虽说做过几题左偏树,但还是很迷….(还有大佬用主席树和启发式合并splay???)
毕竟我不会dfs序…(不会的同僚往下看)
感性的认识,dfs搜到底后慢慢回溯(dfs中的x就是当前的领导者),再连带着堆从下往上合并(如果你枚举领导者,再建堆,是不是很麻烦,多了很多重复的工作)
还有就是我们用工资大小维护大根堆,因为最后的答案是领导力乘人数,当确定了领导者后,要尽量多的人数对吧,但工资不能超过预算,难道你还请贵的……维护大根堆,如果工资超过预算,就把要钱最多的人给踢出去(大家都是人,干嘛你要辣么多钱)

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;int n,m;struct node{    int x,y,next;}a[1100000];int len,last[1100000];struct heap{    int l,r;    LL c,d;    heap()    {        l=r=d=0;    }}h[1100000];int root[1100000];void ins(int x,int y){    len++;    a[len].x=x;a[len].y=y;    a[len].next=last[x];last[x]=len;}int Marge(int x,int y){    if(x==0||y==0)return x+y;    if(h[x].c<h[y].c)swap(x,y);//按工资维护大根堆,踢堆首维护花费小于m方便     h[x].r=Marge(h[x].r,y);    if(h[h[x].l].d<h[h[x].r].d)swap(h[x].l,h[x].r);    h[x].d=h[h[x].r].d+1;    return x;}LL p[1100000],s[1100000];//人数,花费钱数 LL ans,ld[1100000];void dfs(int x)//通过dfs序,使得每个点都成为一个大根堆,涵盖所有情况 {    for(int k=last[x];k;k=a[k].next)    {        int y=a[k].y;        dfs(y);        p[x]+=p[y];s[x]+=s[y];        root[x]=Marge(root[x],root[y]);    }    while(s[x]>m)    {        s[x]-=h[root[x]].c;p[x]--;        root[x]=Marge(h[root[x]].l,h[root[x]].r);    }    if(ld[x]*p[x]>ans)ans=ld[x]*p[x];}int main(){    int B;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        scanf("%d%lld%lld",&B,&h[i].c,&ld[i]);        ins(B,i);p[i]=1;s[i]=h[i].c;root[i]=i;    }    ans=0;dfs(1);    printf("%lld\n",ans);    return 0;}
原创粉丝点击