poj 1984 Navigation Nightmare 带拓展域并查集

https://vjudge.net/problem/POJ-1984#author=0

题目大意:

n个网格状的农田,每个农田之间有距离,会依次给出关系,在给出关系后询问两个农田之间的曼哈顿距离是多少?

若无法判断则输出-1

输入:

对于每组案例:
首先输入两个数字nm,表示有n块农田,农田从1开始编号。
接下来m行,每行给出a,b,l,dab表示农田的编号,l表示之间的距离,d表示bad侧(只有四种,北-N,南-S,西-W,东-E)。
然后输入一个数字k,代表询问次数。
之后输入k行,每行有三个数字a,b,c,表示在c行后询问a,b间的曼哈顿距离是多少?

数据范围:

1<=n,m<=40000

 

带拓展域并查集,假如因为需要知道曼哈顿距离,曼哈顿距离可以拆分成横坐标和纵坐标,并查集的时候维护横坐标和纵坐标就行

 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long 
#define ull unsigned long long 
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 4e4 + 7;
int f1[maxn], f2[maxn], dis[maxn];
char dir[maxn];
int n, m, k;
int fat[maxn], dx[maxn], dy[maxn];
int trace(int x) {
	if (fat[x] == x) {
		return x;
	}
	int f = trace(fat[x]);
	dx[x] += dx[fat[x]];
	dy[x] += dy[fat[x]];
	fat[x] = f;
	return f;
}
void combine(int a, int b,char c,int d) {
	int fa = trace(a), fb = trace(b), flag;
	if (fa != fb) {
		fat[fa] = fb;
		if (c == 'E' || c == 'N')
			flag = 1;
		else
			flag = -1;
		if (c == 'E' || c == 'W') {
			dx[fa] = flag * d + dx[b] - dx[a];
			dy[fa] = dy[b] - dy[a];
		}
		else {
			dy[fa] = flag * d + dy[b] - dy[a];
			dx[fa] = dx[b] - dx[a];
		}
	}

}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) 
		scanf("%d %d %d %c", f1 + i, f2 + i, dis + i, dir + i);
	cin >> k;
	int now = 1;
	int a, b, c;
	for (int i = 1; i <= n; i++)
		fat[i] = i;
	while (k--) {
		scanf("%d %d %d", &a, &b, &c);
		while (now <= c) {
			combine(f1[now], f2[now], dir[now], dis[now]);
			now++;
		}
		int fa = trace(a), fb = trace(b);
		if (fa == fb) {
			printf("%d\n", abs(dx[a] - dx[b]) + abs(dy[a] - dy[b]));
		}
		else
			printf("-1\n");


	}
	return 0;
}

 

你可能感兴趣的:(acm)