【金牌导航】【左偏树】派遣

【金牌导航】【左偏树】派遣

题目

在这里插入图片描述在这里插入图片描述


解题思路

式子为选取节点数*l[R]
发现选取的点越多答案越大
那么每个点的贡献是一样的,这种情况下选取c[i]更小的
维护一个树顶为最大值的左偏树
从下面开始合并,如果c[i]和>m就删除树顶

左偏树
定义距离dis为当前节点去到叶子节点经过右节点的最大值
左偏树的根节点小于等于ta的子节点
左偏树的左节点距离大于等于右节点距离
左偏树支持合并操作

合并操作
把A,B两棵树合并,假设A中所有节点都小于B
选取A中最小的节点作为新树的根
然后合并A的右子树和B
直到有一棵树为空返回另一棵

删除操作
删除一个点,把ta的左右子树合并起来再挂回树上即可
注意合并后可能不满足左偏树的性质,要维护,如果左子树的距离<右子树的距离,就交换
合并后距离要向上传递

插入操作
可以理解为一棵只有一个点的树与左偏树合并

构建新树
方法1:一个点一个点暴力插入,时间复杂度为O(n logn)
方法2:仿照二叉堆的建法,把所有点放进一个先进先出的队列,每次取出两棵树合并,将合并后的树放入队列


代码

#include<iostream>
#include<cstdio>
using namespace std;
struct lzf{
	int to,nxt;
}f[1000010];
struct node{
	int l,r,dis,sl;
	long long c,sum; 
}tree[1000010];
int n,x,t,rt[1000010],head[1000010];
long long m,ans,c[1000010],li[1000010];
void add(int x,int y)
{
	 f[++t]=(lzf){y,head[x]};
	 head[x]=y;
}
int merge(int x,int y)
{
	if (!x) return y;
	if (!y) return x;
	if (tree[x].c<tree[y].c) swap(x,y);
	tree[x].r=merge(tree[x].r,y);
	if (tree[tree[x].l].dis<tree[tree[x].r].dis)
	   swap(tree[x].l,tree[x].r);
	tree[x].dis=tree[tree[x].r].dis+1;
	tree[x].sl=tree[tree[x].l].sl+tree[tree[x].r].sl+1;
	tree[x].sum=tree[tree[x].l].sum+tree[tree[x].r].sum+tree[x].c;
	return x;
}
void dfs(int x,int fa)
{
	for (int i=head[x];i;i=f[i].nxt)
	    if (f[i].to!=fa)
	    {
	    	dfs(f[i].to,x);
	    	rt[x]=merge(rt[x],rt[f[i].to]); //与子树合并
	    	while (tree[rt[x]].sum>m) rt[x]=merge(tree[rt[x]].l,tree[rt[x]].r);  //c[i]>m删除树顶
	    	ans=max(ans,1ll*li[x]*tree[rt[x]].sl);
	    }
	ans=max(ans,1ll*li[x]*tree[rt[x]].sl);  //叶子节点的更新
}
int main()
{
	scanf("%d%lld",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d%lld%lld",&x,&c[i],&li[i]);
		add(x,i);
	}
	for (int i=1;i<=n;i++)
	{
		tree[i]=(node){0,0,-1,1,c[i],c[i]};
		rt[i]=i;
		if (tree[i].sum>m) rt[i]=merge(tree[i].l,tree[i].r);
	}
	dfs(1,0);
	printf("%lld",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值