http://poj.org/problem?id=1984 /*题意:给出点数和边数 已知每一条边的起点终点编号和方向 几个Query,每个Query求两个编号的点在第 I 步之后的曼哈顿距离 将Query按操作步数的大小排序,从小到大 遍历每个操作,执行并集函数,然后如果这步有Query则对Query的两个点执行查集函数,如果在一个集合当中, 他们的曼哈顿距离即为他们的父亲结点的曼哈顿距离,否则输出-1 并集函数写法:如果第x条边(第x 步操作产生的)两个端点不在同一集合,则合并, 注意合并之后作为儿子的结点到父亲结点的曼哈顿距离要有变化,要分边的方向不同考虑,详见代码 查集函数注意x,y 相对距离的累加 */ #include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> using namespace std; #define MAXN 40005 struct Edge { int a, b, w; char dir; }e[MAXN];//储存图 struct query { int a, b, index; }q[10010];//储存询问 struct node { int f, a, b; }v[MAXN]; int n, m, k; char d[] = {'N', 'E', 'S', 'W'}; int dx[] = {0, 1, 0, -1}; int dy[] = {1, 0, -1, 0}; int ex_dir(char c) { for(int i=0; i<4; i++) if(d[i] == c) return i; } bool cmp(query &a, query &b) { return a.index < b.index; } int find_set(int index, int &x, int &y) { int t = index; x = 0; y = 0; while(v[t].f != -1) { x += v[t].a; y += v[t].b; t = v[t].f; } return t; } void union_set(int x) { int x1, y1, x2, y2; int v1 = e[x].a, v2 = e[x].b; int f1 = find_set(v1, x1, y1), f2 = find_set(v2, x2, y2); if(f1 == f2) return; int dd = ex_dir(e[x].dir); v[f2].f = f1; v[f2].a = dx[dd]*e[x].w + x1 - x2; v[f2].b = dy[dd]*e[x].w + y1 - y2; } int main() { // freopen("in.txt", "r", stdin); int i, j, f1, f2, x1, x2, y1, y2; scanf("%d %d", &n, &m); for(i=0; i<m; i++) scanf("%d %d %d %c", &e[i].a, &e[i].b, &e[i].w, &e[i].dir); scanf("%d", &k); for(i=0; i<k; i++) scanf("%d %d %d", &q[i].a, &q[i].b, &q[i].index); sort(q, q+k, cmp); for(i=0; i<=n; i++) v[i].f = -1;//init_set for(i=0, j=0; i<m; i++) { union_set(i); while(j<k && q[j].index <= i+1) { f1 = find_set(q[j].a, x1, y1); f2 = find_set(q[j].b, x2, y2); if(f1 == f2) printf("%d/n", abs(x1-x2) + abs(y1-y2)); else printf("-1/n"); j++; } } // for(i=0; i<n; i++) // printf("%d %d %d/n", v[i].f, v[i].a, v[i].b); return 0; }