[bzoj 2809][Apio2012]dispatching

传送门

Solution

可并堆——左偏树 的模板题

维护大根堆,这样只要达到雇佣薪水的上限,就直接pop堆顶元素就行了


Code 

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
#define MN 100005
int Li[MN],fa[MN],Ci[MN];
int ls[MN],rs[MN],M,val[MN],siz[MN],rt[MN],dis[MN];
ll ans,sum[MN];
struct edge{int to,nex;}e[MN];int hr[MN],en;
inline void ins(int f,int t){e[++en]=(edge){t,hr[f]};hr[f]=en;}
int Merge(int x,int y)
{
	if(!x||!y) return x|y;
	if(val[x]<val[y]) std::swap(x,y);
	rs[x]=Merge(rs[x],y);
	if(dis[rs[x]]>dis[ls[x]]) std::swap(ls[x],rs[x]);
	dis[x]=dis[rs[x]]+1;
	sum[x]=sum[ls[x]]+sum[rs[x]]+val[x];
	siz[x]=siz[ls[x]]+siz[rs[x]]+1;
	return x;
}
inline void Pop(int &x){x=Merge(ls[x],rs[x]);}
void dfs(int x)
{
	register int i;
	for(i=hr[x];i;i=e[i].nex)
	{
		dfs(e[i].to),rt[x]=Merge(rt[x],rt[e[i].to]);
		while(sum[rt[x]]>M) Pop(rt[x]); 	
	}
	ans=max(ans,1ll*Li[x]*siz[rt[x]]);
}
int main()
{
	register int n,i;
	n=read(),M=read();
	for(i=1;i<=n;++i) fa[i]=read(),Ci[i]=read(),Li[i]=read(),ins(fa[i],i);
	for(i=1;i<=n;++i) if(Ci[i]<=M) rt[i]=i,sum[i]=val[i]=Ci[i],dis[i]=siz[i]=1;
	dfs(1);
	printf("%lld\n",ans);
	return 0;
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

posted @ 2018-12-25 11:52  PaperCloud  阅读(136)  评论(0编辑  收藏  举报