Bzoj2809:[Apio2012]dispatching:左偏树

1 篇文章 0 订阅

题目链接:2809:[Apio2012]dispatching

考虑对于以节点x为根的一颗子树,我们只要在m的限制下尽量多地选择忍者即可,这个可以用大根堆维护

考虑x向x的父亲y转移时,相当于y的各颗子树在m的限制下尽可能多的选择忍者,显然我们不能暴力重建堆,用可并堆logn维护即可,这里我用的是左偏树

每转移到一个节点就更新一遍答案

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=200010;
int n,m,tot=1,h[maxn],l[maxn];
int rt[maxn],cnt[maxn],root,num=0;
struct edge{int to,next;}G[maxn*6];
LL ans=0,cost[maxn],c[maxn];
struct LeftIstTree{
	struct treenode{
		int v,l,r,d;
		treenode(){v=l=r=d=0;}
		bool operator < (const treenode &a)const{return v<a.v;}
	};
	treenode t[maxn];
	int newnode(int x){
		num++; t[num].v=c[x]; return num; 
	}
	int merge(int a,int b){
		if(!a||!b)return a+b;
		if(t[a]<t[b])swap(a,b);
		t[a].r=merge(t[a].r,b);
		if(t[t[a].l].d<t[t[a].r].d)swap(t[a].l,t[a].r);
		t[a].d=t[a].r?t[t[a].r].d+1:0;
		return a;
	}
}lit;

void add(int x,int y){
	G[++tot].to=y;G[tot].next=h[x];h[x]=tot;
}

void dfs(int x){
	rt[x]=lit.newnode(x); cost[x]=c[x]; cnt[x]=1;
	if (c[x]<=m) ans=max(ans,1LL*l[x]);
	for (int i=h[x];i;i=G[i].next){
		int v=G[i].to; dfs(v);
		rt[x]=lit.merge(rt[x],rt[v]);
		cost[x]+=cost[v]; cnt[x]+=cnt[v];
		while (cost[x]>m) cost[x]-=lit.t[rt[x]].v,cnt[x]--,
						  rt[x]=lit.merge(lit.t[rt[x]].l,lit.t[rt[x]].r);
		ans=max(ans,1LL*l[x]*cnt[x]);
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i){
		int x; scanf("%d%lld%d",&x,&c[i],&l[i]);
		add(x,i); if (!x) root=i;
	}
	ans=0; dfs(root);
	printf("%lld\n",ans);
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值