可持久化可并堆 例题 题解

OVOO题解:

求包含根节点的第k小连通块的权值,连通块的权值定义为连通块中包含的所有边的权值之和。
使用A* 算法(估价函数为0),维护一个优先队列,优先队列中储存连通块的权值,上一次选的边权和当前连通块周围的可选边集合构成的可并堆,每种状态有如下两种扩展方式:
(1)删除上一次选的边,并选一条当前可选边中权值最小的边。
(2)将上一次选的边的所有出边所构成的可并堆与当前处理状态中的可并堆合并,并从中选出一条权值最小的边,将这条边从可并堆中删除,同时上一条边将不再允许删除。
这种方式保证方案不重复不遗漏,并且每种被扩展完毕的状态,都是一种合法状态,这样保证了算法的时间复杂度。(出队K次即可,每次均为log级),这种扩展方式还使得每次扩展出的状态权值都比大于等于原状态的权值,保证了A*算法的正确性。
为了节省空间,使用可持久化可并堆。
代码:

#include <stdio.h>
#include <queue>
using namespace std;
#define ll long long
int gen[3700010]={0},shu=0;
int l[3700010],r[3700010];
int z[3700010],cd[3700010];
int v[3700010];
int hb1(int x,int y)
{
	if(x==0||y==0)
		return x+y;
	int t;
	if(z[x]>z[y])
		t=x,x=y,y=t;
	r[x]=hb1(r[x],y);
	if(cd[l[x]]<cd[r[x]])
		t=l[x],l[x]=r[x],r[x]=t;
	cd[x]=cd[r[x]]+1;
	return x;
}
int hb2(int x,int y)
{
	if(x==0||y==0)
		return x+y;
	int t,rt;
	if(z[x]>z[y])
		t=x,x=y,y=t;
	shu+=1;
	rt=shu;
	z[rt]=z[x];
	l[rt]=l[x];
	v[rt]=v[x];
	r[rt]=hb2(r[x],y);
	if(cd[l[rt]]<cd[r[rt]])
		t=l[rt],l[rt]=r[rt],r[rt]=t;
	cd[rt]=cd[r[rt]]+1;
	return rt;
}
struct SJd
{
	ll he;
	int wz;
	SJd(){}
	SJd(ll He,int Wz)
	{
		he=He;
		wz=Wz;
	}
};
bool operator<(SJd a,SJd b)
{
	return a.he>b.he;
}
int main()
{
	cd[0]=-1;
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=2;i<=n;i++)
	{
		int f,x;
		scanf("%d%d",&f,&x);
		shu+=1;
		z[shu]=x;
		v[shu]=i;
		gen[f]=hb1(gen[f],shu);
	}
	shu+=1;
	v[shu]=1;
	priority_queue <SJd> pq;
	pq.push(SJd(0,shu));
	SJd jd;
	for(int i=0;i<k;i++)
	{
		if(pq.empty())
			break;
		jd=pq.top();
		pq.pop();
		int la=z[jd.wz],vv=v[jd.wz];
		jd.wz=hb2(l[jd.wz],r[jd.wz]);
		if(jd.wz!=0)
			pq.push(SJd(jd.he-la+z[jd.wz],jd.wz));
		jd.wz=hb2(jd.wz,gen[vv]);
		if(jd.wz!=0)
			pq.push(SJd(jd.he+z[jd.wz],jd.wz));
	}
	printf("%lld",jd.he%998244353);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值