[BZOJ2809][Apio2012]dispatching(枚举&dfs序+主席树||可并堆||splay+启发式合并)

题目描述

传送门

题解

1° 主席树
枚举每一个忍者当管理者,由于选忍者的顺序满足薪水单调不减,可以用dfs序+主席树维护出子树中权值之和小于等于k最多有多少个。维护的时候需要维护sum权值和以及s满足条件的忍者的个数。注意建的是权值线段树。

2° 可并堆

3°splay+启发式合并

代码

主席树

#include
#include
#include
#include
using namespace std;
#define LL long long

const int max_n=1e5+5;
const int max_e=max_n*2;
const int max_tree=max_n*20;
int n,fa,sz,N,p[max_n],a[max_n],root[max_n],num[max_n],num1[max_n],in[max_n],out[max_n],val[max_n],ls[max_tree],rs[max_tree];
int tot,point[max_n],next[max_e],v[max_e];
LL k,kk,calc,calck,power[max_n],ans,sum[max_tree],s[max_tree];

inline int cmp(int x,int y){return a[x]inline void addedge(int x,int y){++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y;}
inline void dfs(int x){
    in[x]=++N; val[N]=a[x]; num[N]=num1[x];
    for (int i=point[x];i;i=next[i]) dfs(v[i]);
    out[x]=N;
}
inline void build(int &now,int l,int r,int x,int v){
    int mid=(l+r)>>1;
    sum[++sz]=(LL)sum[now]+(LL)v,s[sz]=s[now]+1,ls[sz]=ls[now],rs[sz]=rs[now],now=sz;
    if (l==r) return;
    if (x<=mid) build(ls[now],l,mid,x,v);
    else build(rs[now],mid+1,r,x,v);
}
inline int query(int a,int b,int l,int r,LL k){
    int mid=(l+r)>>1;
    if (l==r){
        if (sum[b]-sum[a]!=0&&calck+sum[b]-sum[a]<=kk) return calc+1;
        else return calc;
    }
    LL t=sum[ls[b]]-sum[ls[a]];
    if (t>=k) return query(ls[a],ls[b],l,mid,k);
    else {calc+=s[ls[b]]-s[ls[a]]; calck+=t; return query(rs[a],rs[b],mid+1,r,k-t);}
}
int main(){
    scanf("%d%lld",&n,&k);kk=k;
    for (int i=1;i<=n;++i){
        p[i]=i;
        scanf("%d%d%lld",&fa,&a[i],&power[i]);
        if (fa) addedge(fa,i);
    }
    sort(p+1,p+n+1,cmp);
    for (int i=1;i<=n;++i) num1[p[i]]=i;
    dfs(1);
    root[0]=sz=0;
    for (int i=1;i<=n;++i){
        root[i]=root[i-1];
        build(root[i],1,n,num[i],val[i]);
    }
    for (int i=1;i<=n;++i){
        int l=in[i]-1,r=out[i];
        calc=calck=0; 
        LL cnt=query(root[l],root[r],1,n,k);
        if (power[i]*cnt>ans) ans=power[i]*cnt;
    }
    printf("%lld",ans);
}

总结

1°‘主席树’本来可以1A的题因为%I64d嘿嘿嘿了

你可能感兴趣的:(题解,贪心,可持久化,dfs序)