#左偏树,树形dp#洛谷 1552 [APIO2012]派遣

题目


分析

那我指定管理层之后,选择薪水越小的人越好,
考虑小根堆,由于需要合并,所以采用左偏树


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=100011; typedef long long lll;
struct node{int y,next;}e[N];
int n,siz[N],lead[N],as[N],et; lll ans,m,c[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
struct Leftist_Tree{
	int rt[N],son[N][2],w[N],d[N];
	inline signed Merge(int fi,int se){
		if (!fi||!se) return fi|se;
		if (w[fi]<w[se]) swap(fi,se);
		son[fi][1]=Merge(son[fi][1],se);
		if (d[son[fi][0]]<d[son[fi][1]]) swap(son[fi][0],son[fi][1]);
		d[fi]=d[son[fi][1]]+1;
		return fi;
	}
	inline signed Pop(int now){
		rr int t1=son[now][0],t2=son[now][1];
		rt[t1]=t1,rt[t2]=t2,w[now]=-1,
		son[now][0]=son[now][1]=d[now]=0;
		return Merge(t1,t2);
	}
}Tre;
inline void dfs(int x){
	for (rr int i=as[x];i;i=e[i].next){
		dfs(e[i].y);
		Tre.rt[x]=Tre.Merge(Tre.rt[x],Tre.rt[e[i].y]);
		c[x]+=c[e[i].y],siz[x]+=siz[e[i].y];
	}
	while (c[x]>m){
		c[x]-=Tre.w[Tre.rt[x]],--siz[x],
		Tre.rt[x]=Tre.Pop(Tre.rt[x]);
	}
	ans=max(ans,1ll*lead[x]*siz[x]);
}
signed main(){
	n=iut(),m=iut(),Tre.d[0]=-1;
	for (rr int i=1;i<=n;++i){
		rr int F=iut(); if (F) e[++et]=(node){i,as[F]},as[F]=et;
		c[i]=Tre.w[i]=iut(),Tre.rt[i]=i,lead[i]=iut(),siz[i]=1;
	}
	dfs(1);
	return !printf("%lld",ans);
} 
posted @ 2020-11-26 14:27  lemondinosaur  阅读(75)  评论(0编辑  收藏  举报