BZOJ2809

BZOJ2809 [Apio2012]dispatching

Description

N 个忍者及一个Master,忍者从1 ~N 编号,Master编号为0,忍者之间有从属关系,上级的编号一定比下属小。

每个忍者有一个工资和领导能力值。

现要求派出一些忍者并确定一名领导者,派出忍者要支付工资。领导者也可以被派出,但派出就付工资,不派出就不用,领导者必须是派出的所有忍者的上级(祖先)。

求:在预算范围内派出的忍者数*领导者的领导能力值。

input

第一行:NMN 表示忍者数,M 表示工资总预算。

接下来NBiCiLi ,其中Bi 表示上级,Ci 表示工资,Li 表示领导能力值。

output

一行,一个数:答案。

题解

用主席树做。

建起来明显就是一棵树。

按DFS遍历一遍(前序遍历)并记录每个点进去和出来的时间。

以工资大小顺序为下标,累加总工资和人数。

再以这个时间为顺序把点一个一个加进去,更新他父亲那颗树。

然后枚举每个点,可以知道每个点的子孙的时间就在他进去和出去的时间的范围内。

出去时间时的线段树减去进去时间时的线段树就是它子孙的了。

code

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=100100;
int n,m;
long long ans;
struct Ninja
{
    int fa,cost,l;
}ninja[maxn];
struct EDGE
{
    int ap;
    EDGE *next;
}edge[maxn],*ind[maxn];
int el;
void input(int x,int y)
{
    edge[++el].ap=y;
    edge[el].next=ind[x];
    ind[x]=&edge[el];
}

struct idnk
{
    int num,adr;
}b[maxn];
int c[maxn];
bool cmp(idnk x,idnk y){return x.num<y.num;}
void dis()
{
    sort(b+1,b+1+n,cmp);
    for(int i=1;i<=n;i++) c[b[i].adr]=i;
}


int T,din[maxn],dout[maxn],d[maxn];
void dfs(int x)
{
    din[x]=++T;
    d[T]=x;
    for(EDGE *k=ind[x];k!=NULL;k=k->next)
        dfs(k->ap);
    dout[x]=T;
}

struct TREE
{
    long long sumc;
    long long sumn;
    TREE *l,*r;
}tree[maxn*20],*root[maxn];
int tl;
TREE *build(int l,int r)
{
    int N=++tl;
    if(l==r) return &tree[N];

    int mid=(l+r)/2;
    tree[N].l=build(l,mid);
    tree[N].r=build(mid+1,r);
    return &tree[N]; 
}

TREE *update(int l,int r,int find,int add,TREE *k)
{
    int N=++tl;
    if(l==r)
    {
        tree[N].sumc=k->sumc+add;
        tree[N].sumn=1;
        return &tree[N];
    }
    int mid=(l+r)/2;
    if(find<=mid) tree[N].l=update(l,mid,find,add,k->l),tree[N].r=k->r;
    else tree[N].l=k->l,tree[N].r=update(mid+1,r,find,add,k->r);
    tree[N].sumc=tree[N].l->sumc+tree[N].r->sumc;
    tree[N].sumn=tree[N].l->sumn+tree[N].r->sumn;
    return &tree[N];
}

long long work(int l,int r,long long maxm,TREE *tl,TREE *tr)
{
    if(l==r) return tr->sumc-tl->sumc<=maxm ? 1 : 0;
    int mid=(l+r)/2;
    if(tr->sumc-tl->sumc<=maxm) return tr->sumn-tl->sumn;
    else if(tr->l->sumc-tl->l->sumc>maxm) return work(l,mid,maxm,tl->l,tr->l);
    else return tr->l->sumn-tl->l->sumn+work(mid+1,r,maxm-tr->l->sumc+tl->l->sumc,tl->r,tr->r);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&ninja[i].fa,&ninja[i].cost,&ninja[i].l);
        b[i].adr=i;
        b[i].num=ninja[i].cost;
        input(ninja[i].fa,i);
    }
    dis();
    for(EDGE *k=ind[0];k!=NULL;k=k->next)
        dfs(k->ap);
    root[0]=build(1,n);
    for(int i=1;i<=n;i++) root[i]=update(1,n,c[d[i]],ninja[d[i]].cost,root[i-1]);

    for(int i=1;i<=n;i++)
    {
        long long sumn=work(1,n,m,root[din[i]-1],root[dout[i]]);
        ans=max(ans,sumn*ninja[i].l);
    }
    printf("%lld",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章