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

题目链接:http://poj.org/problem?id=1984

题意:题目是说给你n个线,并告知其方向,然后对于后面有一些询问,每个询问有一个时间点,要求你输出在该时间点a,b的笛卡尔距离,如果不存在则输出-1

其实就是将权值分一下x,y,x表示x轴方向的权值,y表示y轴方向的权值。然后最后询问时稍微有点技巧

可以先记录一下每次询问的位置然后再按照时间点从小到大来排序最后这样就方便并查集了。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
const int M = 4e4 + 10;
int n , m , f[M] , ans[M];
struct TnT {
    int x , y , num , pos , sum;
    char aim;
}root[M] , T[M] , qu[M];
bool cmp(TnT a , TnT b) {
    return a.num < b.num;
}
int find(int x) {
    if(x == f[x])
        return x;
    int tmp = find(f[x]);
    root[x].x += root[f[x]].x;
    root[x].y += root[f[x]].y;
    return f[x] = tmp;
}
void Union(int x , int y , int addx , int addy) {
    int a = find(x) , b = find(y);
    if(a != b) {
        f[a] = b;
        root[a].x = root[y].x - root[x].x - addx;
        root[a].y = root[y].y - root[x].y - addy;
    }
}
int main() {
    int x , y , l , q;
    char cp[2];
    scanf("%d%d" , &n , &m);
    for(int i = 1 ; i <= m ; i++) {
        scanf("%d%d%d%s" , &x , &y , &l , cp);
        T[i].x = x , T[i].y = y , T[i].sum = l , T[i].aim = cp[0];
    }
    for(int i = 1 ; i <= n ; i++) {
        f[i] = i , root[i].x = 0 , root[i].y = 0;
    }
    scanf("%d" , &q);
    for(int i = 1 ; i <= q ; i++) {
        scanf("%d%d%d" , &qu[i].x , &qu[i].y , &qu[i].num);
        qu[i].pos = i;
    }
    sort(qu + 1 , qu + 1 + q , cmp);
    int temp = 1;
    for(int i = 1 ; i <= q ; i++) {
        for(int j = temp ; j <= qu[i].num ; j++) {
            x = T[j].x , y = T[j].y , l = T[j].sum;
            if(T[j].aim == ‘W‘)
                Union(x , y , -l , 0);
            if(T[j].aim == ‘E‘)
                Union(x , y , l , 0);
            if(T[j].aim == ‘N‘)
                Union(x , y , 0 , l);
            if(T[j].aim == ‘S‘)
                Union(x , y , 0 , -l);
        }
        temp = qu[i].num + 1;
        int a = find(qu[i].x) , b = find(qu[i].y);
        if(a != b)
            ans[qu[i].pos] = -1;
        else
            ans[qu[i].pos] = abs(root[qu[i].x].x - root[qu[i].y].x) + abs(root[qu[i].x].y - root[qu[i].y].y);
    }
    for(int i = 1 ; i <= q ; i++) {
        printf("%d\n" , ans[i]);
    }
    return 0;
}
时间: 2024-10-13 11:35:24

poj 1984 Navigation Nightmare(带权并查集+小小的技巧)的相关文章

BZOJ 3362 POJ 1984 Navigation Nightmare 带权并查集

题目大意:一些农场由一些东西向或者南北向的路相互连接.在不断加边的过程中会询问两个农场的曼哈顿距离是多少,如果目前还不连通,那么输出-1. 思路:带权并查集,f[i]为点i到father[i]的距离,要维护两个值,一个是东西向的距离,一个是南北向的距离,因为以后更新的时候要用到.在合并的时候有些特殊.现在有一条边(x->y),设fx为x的根,fy为y的根,那么现在知道f到fx的距离,y到fy的距离,还知道x到y的距离,设fx到fy的距离为dis,则dis + f[y] = f[x] + edge

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

题目链接:http://poj.org/problem?id=1984 Time Limit: 2000MS Memory Limit: 30000K Case Time Limit: 1000MS Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usually numbered/labeled 1..N. A series of M (1 <= M < 40,000)

POJ 1984 Navigation Nightmare (数据结构-并查集)

Navigation Nightmare Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 4072   Accepted: 1615 Case Time Limit: 1000MS Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usually numbered/labeled 1..N. A series o

BZOJ 3362 Navigation Nightmare 带权并查集

题目大意:给定一些点之间的位置关系,求两个点之间的曼哈顿距离 此题土豪题,不过POJ也有一道同样的题,可以刷一下 别被题目坑到了,这题不强制在线,把询问离线处理即可 然后就是带权并查集的问题了...将权值设为方向向量,重载+和-,按照正常权值并查集做就行了 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 40400 using namesp

Navigation Nightmare——带权并查集(多权值)

题目链接 题意: 给出n个农场,然后按时间依次给出m个关于农场相对位置的信息,之后会给出询问,问在t时刻,x到y的曼哈顿距离是多少. 题解: dx[i]维护 根节点到 i 的横坐标距离   dy[i]维护 根节点到 i 的纵坐标距离 并查集高效的地方就在于在使用Find(x)函数查找x的父结点的时候会把沿途递归访问到的所有结点直接连到父节点上,使得下一次查询可以直接找到父节点,代码表示就是f[x]=Find(f[x]); 之前接触到的都是比较裸的并查集,但就像这题,维护并查集的时候还需要维护点到

poj 2912 Rochambeau(带权并查集 + 暴力)

题目:poj 2912 Rochambeau(带权并查集 + 暴力) 题目大意:题目给出三个团队和一个裁判,这三个团队和裁判一起玩剪刀石头布,然后规定每个团队必须出一样的,只有裁判可以任意出.然后给出关系,x > y 代表 x 赢y , x < y代表 y 赢 x , 相等则出的一样.问这样的关系可以推出裁判是哪个吗?可以需要说明从第一条到第几条推出来的,不可以也要说明是不可能出现这样的关系,还是裁判不唯一. 解题思路:这题重点是裁判在里面会扰乱关系,并且n * m 才 100000,完全可以

POJ 1988 Cube Stacking (带权并查集)

题目链接:http://poj.org/problem?id=1988 有n个元素,开始每个元素自己 一栈,有两种操作,将含有元素x的栈放在含有y的栈的顶端,合并为一个栈.第二种操作是询问含有x元素下面有多少个元素. 经典的带权并查集,cnt表示包含这个元素的集合中所有元素个数,dis表示这个元素离最上面元素的个数(距离). 看代码领会一下吧. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio>

POJ 1182 食物链(带权并查集)

http://poj.org/problem?id=1182 题意: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类. 第二种说法是"2 X Y",表示X吃Y. 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话

POJ 1773 Parity game 带权并查集

分析:带权并查集,就是维护一堆关系 然后就是带权并查集的三步 1:首先确定权值数组,sum[i]代表父节点到子节点之间的1的个数(当然路径压缩后代表到根节点的个数) 1代表是奇数个,0代表偶数个 2:设计路径压缩算法 sum[x]=(sum[x]+sum[t])%2; 3:弄清合并根节点时的操作,小的在上: 注:这个题需要离散化 #include <stdio.h> #include <string.h> #include <algorithm> using names