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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章