ZOJ 2334 可并堆<斜堆>

35 篇文章 0 订阅
32 篇文章 1 订阅

thinking:1、可以为大根堆或者小根堆,相当于优先队列,但是有合并这个功能

关键代码是

int merge(int x,int y){
if(tree[x].weight==0)return y;
if(tree[y].weight==0)return x;
if(tree[x].weight<tree[y].weight)swap(x,y);     //只是改变x与y的数字 
tree[x].rch=merge(tree[x].rch,y);
swap(x,y);
return x;
}

通过把2个斜堆的根结点对比,求大的或小的放在根结点,然后交换其子结点,递归操作。

代码:

#include <bits/stdc++.h>
using namespace std;
struct ttt{
	int weight,lch,rch;
};
ttt tree[100000+5];
int n;
int pre[100000+5];
void init1(){
	for(int i=1;i<=n;i++)
		pre[i]=i;
	//	cout << pre[i] << endl;}
}
int find(int x){
	while(x!=pre[x])
	x=pre[x];
	return x;
}
int merge(int x,int y){
	if(tree[x].weight==0)return y;
	if(tree[y].weight==0)return x;
	if(tree[x].weight<tree[y].weight)swap(x,y);     //只是改变x与y的数字 
	tree[x].rch=merge(tree[x].rch,y);
	swap(tree[x].lch,tree[y].rch);
	return x;
}
int fun(int t1,int t2){
	int x=find(t1),y=find(t2);
	if(x==y)return -1;
	int ans,xx,yy,tt;
	tt=tree[x].weight>tree[y].weight?tree[x].weight:tree[y].weight;
	ans=merge(tree[x].lch,tree[x].rch);  //将其根节点的左右2个节点再合并。 
	tree[x].weight/=2;
	tree[x].rch=tree[x].lch=0;
	xx=merge(x,ans);
	tree[y].weight/=2;
	ans=merge(tree[y].lch,tree[y].rch);  //将其根节点的左右两个节点再合并,此时的ans为根结点,最大或最小 
	tree[y].rch=tree[y].lch=0;
	yy=merge(y,ans);
	int p=merge(xx,yy);      //并查集思想,前驱就是他们的根节点 
 	pre[xx]=pre[yy]=pre[x]=pre[y]=pre[t1]=pre[t2]=p;
	 return  tt/2;
}
int main(){
	freopen("in.txt","r",stdin);
	memset(tree,0,sizeof(tree));
	int m,i,j,k,l,f1,f2;
	cin >> n;
	init1();
	for(i=1;i<=n;i++)
		cin >> tree[i].weight;
		cin >> m;
		for(i=1;i<=m;i++){
			cin >> f1 >> f2;
		//	cout << find(f1) << find(f2) << endl;
			int g=fun(f1,f2);
			cout << g<< endl;}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值