首页 > 代码库 > POJ 1984 Navigation Nightmare 二维带权并查集

POJ 1984 Navigation Nightmare 二维带权并查集

题目来源:POJ 1984 Navigation Nightmare

题意:给你一颗树 k次询问 求2点之间的曼哈顿距离 并且要在只有开始k条边的情况下

思路:按照方向 我是以左上角为根 左上角为原点 dx[i]为i点距离根的x坐标 dy[]是y坐标 这两个可以通过路径压缩求出 只不过是二维而已

#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int maxn = 40010;
int f[maxn], dx[maxn], dy[maxn];

struct node
{
	int u, v, w;
	char s[3];
}a[maxn];
void init(int n)
{
	for(int i = 1; i <= n; i++)
		f[i] = i;
	memset(dx, 0, sizeof(dx));
	memset(dy, 0, sizeof(dy));
}

int find(int x)
{
	if(x != f[x])
	{
		int rt = find(f[x]);
		dx[x] += dx[f[x]];
		dy[x] += dy[f[x]];
		f[x] = rt;
		return rt;
	}
	return x;
}
int main()
{
	
	int n, m;
	scanf("%d %d", &n, &m);
	init(n);
	for(int i = 1; i <= m; i++)
	{
		scanf("%d %d %d %s", &a[i].u, &a[i].v, &a[i].w, a[i].s);
	}
	int q;
	scanf("%d", &q);
	int i = 1;
	while(q--)
	{
		int s, e, w;
		scanf("%d %d %d", &s, &e, &w);
		while(i <= m && i <= w)
		{
			int u = a[i].u;
			int v = a[i].v;
			int x = find(u);
			int y = find(v);
			if(x == y)
				continue;
			if(a[i].s[0] == 'E')
			{
				f[y] = x;
				dx[y] = dx[u]-dx[v]+a[i].w;
				dy[y] = dy[u]-dy[v];
			}
			else if(a[i].s[0] == 'W')
			{
				f[x] = y;
				dx[x] = dx[v]-dx[u]+a[i].w;
				dy[x] = dy[v]-dy[u];
			}
			else if(a[i].s[0] == 'N')
			{
				f[x] = y;
				dy[x] = dy[v]-dy[u]+a[i].w;
				dx[x] = dx[v]-dx[u];
			}
			else
			{
				f[y] = x;
				dy[y] = dy[u]-dy[v]+a[i].w;
				dx[y] = dx[u]-dx[v];
			}
			i++;
		}	
		
		int x = find(s);
		int y = find(e);
		if(x == y)
		{
			int d = abs(dx[s]-dx[e]) + abs(dy[s]-dy[e]);
			printf("%d\n", d);
		}
		else
		{
			puts("-1");
		}
	}
	return 0;
}