UVALive 6187_Never Wait for Weights(带权并查集)

题目:UVALive 6187


题型:数据结构


题意:

n个人,m个操作,操作方式有两种:

 ! a b w 表示b比a高w;

? a b    询问b比a高多少(可以是负数),如果无法得到答案,输出“UNKNOWN”。


分析:

      由于n和m范围为10^6,所以建图之后每次更新之后求最短路是行不通的,所以为了压缩路径以提高查询效率,需要采用并查集。

      我们设rank(x)为x节点到其根节点的差值,查找x的祖先的时候,每次递归都更新当前节点的rank值。
      有点绕脑子的地方就是合并两个集合。对于更新操作! a b w,如果a和b不在同一个集合,需要将这两个集合合并。

      设roota为a的祖先,rootb为b的祖先,那么有rank(rootb) = w + rank(a) - rank(b),这样两个集合的rank值就一致了。


代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define MAXN 1234567
using namespace std;

int n,m;
char ch[3];

int father[MAXN];//father[x]表示x的父节点
int rank[MAXN];//rank[x]表示x的秩
void Make_Set(int x){//初始化
	father[x] = x;
	rank[x] = 0;
}
int Find_Set(int x){
	if(x != father[x]){
		int tmp = Find_Set(father[x]);
		rank[x] += rank[father[x]];
		father[x] = tmp;
	}
	return father[x];
}
void Union(int a,int b,int w){
	int roota = Find_Set(a);
	int rootb = Find_Set(b);
	if(roota == rootb) return;
	else{
		rank[rootb] = w + rank[a] - rank[b];
		father[rootb] = father[roota];
	}
}

int main(){
	int a,b,w;
	while(1){
		scanf("%d%d",&n,&m);
		if(n == 0 && m == 0) break;
		for(int i=0;i<=n;i++){
			Make_Set(i);
		}
		while(m--){
			scanf("%s",ch);
			if(ch[0] == '!'){
				scanf("%d%d%d",&a,&b,&w);
				Union(a,b,w);	
			}

			else{
				scanf("%d%d",&a,&b);
				int aa = Find_Set(a);
				int bb = Find_Set(b);
				if(aa == bb){
					printf("%d\n",rank[b] - rank[a]);
				}
				else{
					puts("UNKNOWN");
				}
			}
		}

	}

	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值