思路:记录每个点与其根结点的横向距离和纵向距离,当知道其父节点与根结点的关系,很容易推出当前节点与根结点的关系:

直接相加即可。

int p = a[x].par;
a[x].dx += a[p].dx;
a[x].dy += a[p].dy;

合并什么的就不多说了,很容易得出。

值得一说的就是需要按照合并节点的顺序把询问排序,最后按照询问的顺序再排一次序。

AC代码

#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair<int, int>
typedef long long LL;
const int maxn = 40000 + 5;
struct node{
	int par;
	int dx, dy;
}a[maxn];

struct Edge{
	int u, v, dis, ch;
}b[maxn];

struct Question{
	int u, v, t, num;
}q[10000+5];

void init(int n) {
	for(int i = 1; i <= n; ++i) {
		a[i].par = i;
		a[i].dx = a[i].dy = 0;
	}
}

int find(int x) {
	if(a[x].par == x) return x;
	int r = find(a[x].par);
	int p = a[x].par;
	a[x].dx += a[p].dx;
	a[x].dy += a[p].dy;
	return a[x].par = r;
}

void unionset(int x, int y, int dx, int dy) {
	int rx = find(x), ry = find(y);
	if(rx != ry) {
		a[rx].par = y;
		a[rx].dx = dx - a[x].dx;
		a[rx].dy = dy - a[x].dy;
	}
}

int get_dis(int x, int y) {
	int rx = find(x), ry = find(y);
	if(rx != ry) return -1;
	return abs(a[x].dx - a[y].dx) + abs(a[x].dy - a[y].dy);
}

bool cmp1(const Question &a, const Question &b) {
	return a.t < b.t;
}

bool cmp2(const PI &a, const PI &b) {
	return a.second < b.second;
}

int main() {
	int n, m, Q;
	while(scanf("%d%d", &n, &m) == 2) {
		init(n);
		for(int i = 1; i <= m; ++i) {
			scanf("%d %d %d %c", &b[i].u, &b[i].v, &b[i].dis, &b[i].ch);
			//printf("%d %d %d %c\n", b[i].u, b[i].v, b[i].dis, b[i].ch);
		}
		scanf("%d", &Q);
		for(int i = 1; i <= Q; ++i) {
			scanf("%d%d%d", &q[i].u, &q[i].v, &q[i].t);
			q[i].num = i;
		}
		vector<PI>ans;
		sort(q+1, q+Q+1, cmp1);
		int ind = 1;
		for(int i = 1; i <= m; ++i) {
			int dx, dy;
			switch(b[i].ch) {
				case 'E': dx = b[i].dis, dy = 0; break;
				case 'W': dx = -b[i].dis, dy = 0; break;
				case 'N': dx = 0, dy = b[i].dis; break;
				case 'S': dx = 0, dy = -b[i].dis; break;
			}
			unionset(b[i].u, b[i].v, dx, dy);
			while(ind <= Q && q[ind].t == i) {
				ans.push_back(make_pair(get_dis(q[ind].u, q[ind].v), q[ind].num));
				++ind;
			}
		}
		sort(ans.begin(), ans.end(), cmp2);
		for(int i = 0; i < ans.size(); ++i) printf("%d\n", ans[i].first);
	}
	return 0;
}

如有不当之处欢迎指出!

POJ - 1984 Navigation Nightmare 种类并查集的更多相关文章

  1. POJ1984 Navigation Nightmare —— 种类并查集

    题目链接:http://poj.org/problem?id=1984 Navigation Nightmare Time Limit: 2000MS   Memory Limit: 30000K T ...

  2. POJ 1984 Navigation Nightmare 【经典带权并查集】

    任意门:http://poj.org/problem?id=1984 Navigation Nightmare Time Limit: 2000MS   Memory Limit: 30000K To ...

  3. poj 1182:食物链(种类并查集,食物链问题)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 44168   Accepted: 12878 Description ...

  4. poj 1182 食物链(种类并查集 ‘初心者’)

    题目链接:http://poj.org/problem?id=1182 借着这题可以好好理解一下种类并查集,这题比较简单但挺经典的. 题意就不解释了,中问题. 关于种类并查集结局方法也是挺多的 1扩增 ...

  5. POJ 1984 Navigation Nightmare 带全并查集

    Navigation Nightmare   Description Farmer John's pastoral neighborhood has N farms (2 <= N <= ...

  6. POJ 1984 - Navigation Nightmare - [带权并查集]

    题目链接:http://poj.org/problem?id=1984 Time Limit: 2000MS Memory Limit: 30000K Case Time Limit: 1000MS ...

  7. POJ 1984 Navigation Nightmare(二维带权并查集)

    题目链接:http://poj.org/problem?id=1984 题目大意:有n个点,在平面上位于坐标点上,给出m关系F1  F2  L  D ,表示点F1往D方向走L距离到点F2,然后给出一系 ...

  8. poj 1984 Navigation Nightmare(带权并查集+小小的技巧)

    题目链接:http://poj.org/problem?id=1984 题意:题目是说给你n个线,并告知其方向,然后对于后面有一些询问,每个询问有一个时间点,要求你输出在该时间点a,b的笛卡尔距离,如 ...

  9. POJ 1182 食物链(种类并查集)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 63592   Accepted: 18670 Description ...

随机推荐

  1. python初识 - day4

    一.集合(set) 1.集合的定义 set 是一个无序的元素集合,支持并.交.差及对称差等数学运算, 但由于 set 不记录元素位置, 因此不支持索引.分片等类序列的操作. 2.集合的创建 大括号或 ...

  2. Spring ioc,aop的理解

    什么是控制反转? 控制反转是一种将组件依赖关系的创建和管理置于程序外部的技术. 由容器控制程序之间的关系,而不是由代码直接控制 由于控制权由代码转向了容器,所以称为反转 依赖注入,作用是避免手工在各代 ...

  3. shell中awk printf的用法

    打印输出时,可能需要指定字段间的空格数,从而把列排整齐.在print函数中使用制表符并不能保证得到想要的输出,因此,可以用printf函数来格式化特别的输出. printf函数返回一个带格式的字符串给 ...

  4. 【转】matlab图形句柄详解(一)

    在matlab中,每一个对象都有一个数字来标识,叫做句柄.当每次创建一个对象时,matlab就为它建立一个唯一的句柄,句柄中包含有该对象的相关信息参数,可以在后续程序中进行操作,改变其中的参数,以便达 ...

  5. Android图像数据传递到C++的一些坑

    最近在做一个Android图象识别的app, 通过相机预览或者是拍照功能获取图像数据,然后将图像数据传递到本地C++的图像识别so库.在这个过程中花的时间最多的就是数据传输问题.谨以此坑,警示未来!  ...

  6. 配置redis开机自启动和监听

    redis安装好后,每次手动启动很不方便,配置开机自启动. 方法一:设置启动命令到/etc/rc.d/rc.local rc.local文件是系统全局脚本文件,会在其他开机进程脚本文件执行完毕后执行该 ...

  7. JavaScript 基本语法 -- 运算符的优先级

    在所有的运算里,都是有运算顺序的.小时候学四则运算的时候,我们都知道这么一个规则:先乘除后加减,有括号要先算括号! 同样的,在JavaScript里面,运算符也是有相应的优先级的.其优先级如下表所示, ...

  8. python3中的进程

    由于GIL的存在,python中的多线程并不是真正的多线程. 如果想要充分的使用多核CPU的资源,在python中大部分情况需要使用多进程. 在计算机中,进程与进程这之间在内存中是相互独立的,是两块完 ...

  9. wpf datagrid row height 行高自动计算使每行行高自适应文本

    wpf 的datagrid的行高 要么是Auto,要么是定值:但会带来麻烦就是每行行高都一样. 当需要按内容(主要是wrap 换行的textbox或textblock)来动态调整行高的时候,需要用到d ...

  10. 洛谷 [P1963] [NOI2009] 变换序列

    这是一道二分图匹配的题 先%dalao博客 建图并没有什么难的,但是关键在于如何使字典序最小. 一个很显然的想法是先求出一个完美匹配,然后从x集合的第一个元素开始,如果该元素匹配的较小的一个,那么继续 ...