poj 1984 带权并查集 距离

题意:n个地点,现在建设m条南北方向或东西方向的路,这些路是无向的,但是给出的路的信息是这种形式:1 3 15 E,表示从第1个点向东行驶15个距离会到达第3个点。现在有一些这种形式的询问:1 6 2,在建造完第2条路后,1和6的曼哈顿距离是多少。

题解:带权并查集

1.带权并查集模板题。

2.权值是点与点之间的横纵坐标距离。

3.注意:相对距离是相加的,而不是相减的,例如2和1的横坐标距离为-10,3和2的横坐标距离相差-20,那么可知3和1的横坐标距离相差(-20)+(-10)=-30,而不是(-20)-(-10)=-10,画一画图就知道了。

4.注意:合并根节点时需要画图思考细节。

#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#define N 40005
using namespace std ;
int n , m , k ;
struct Edge
{
	int u , v , len ;
	char dir[5] ;
} edge[N] ;
struct Query
{
	int f1 , f2 , index , mark , ans ;
} query[N] ;
struct Node
{
	int pre ;
	int x , y ;
} node[N] ;
bool cmp1(Query a , Query b)
{
	return a.index < b.index ;
}
bool cmp2(Query a , Query b)
{
	return a.mark < b.mark ;
}
int find(int x)
{
	int temp = node[x].pre ;
	if(x != temp)
	{
		node[x].pre = find(node[x].pre) ;
		node[x].x += node[temp].x ;
		node[x].y += node[temp].y ;
	}
	return node[x].pre ;
}
void join(int x)
{
	int u , v ;
	int ru , rv ;
	int disx = 0 , disy = 0 ;
	u = edge[x].u , v = edge[x].v ;
	ru = find(u) ;
	rv = find(v) ;
	if(edge[x].dir[0] == 'E')
	   disx = edge[x].len ;
	else if(edge[x].dir[0] == 'W')
	   disx = -edge[x].len ; 
	else if(edge[x].dir[0] == 'N')
	   disy = edge[x].len ;  
	else if(edge[x].dir[0] == 'S')
	   disy = -edge[x].len ;    
	if(ru != rv)
	{
       node[ru].pre = rv ;
       node[ru].x = node[v].x - node[u].x - disx ; 
       node[ru].y = node[v].y - node[u].y - disy ;
	}
}
int main()
{
	int i , j ;
	int update ;
	int u , v ;
	scanf("%d%d" , &n , &m) ;
	for(i = 1 ; i <= m ; i ++)
        scanf("%d%d%d%s" , &edge[i].u , &edge[i].v , &edge[i].len , &edge[i].dir) ;
    scanf("%d" , &k) ;
    for(i = 1 ; i <= k ; i ++)
    {
       scanf("%d%d%d" , &query[i].f1 , &query[i].f2 , &query[i].index) ;
	   query[i].mark = i ;
	   query[i].ans = -1 ;	
	}
    for(i = 1 ; i <= n ; i ++)
    {
    	node[i].pre = i ;
    	node[i].x = 0 ;
    	node[i].y = 0 ;
	}
	sort(query + 1 , query + k + 1 , cmp1) ;    
	update = 0 ;
	for(i = 1 ; i <= k ; i ++)
	{
		while(update < query[i].index)
		{
			update ++ ;
			join(update) ;
		}
		u = query[i].f1 , v = query[i].f2 ;
		if(find(u) == find(v))
		   query[i].ans = abs(node[u].x - node[v].x) + abs(node[u].y - node[v].y) ;
	}
	sort(query + 1 , query + k + 1 , cmp2) ; 
	for(i = 1 ; i <= k ; i ++)
	    printf("%d\n" , query[i].ans) ;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值