hrbust 哈理工oj 1418 夏夜星空【带权并查集】

夏夜星空
Time Limit: 1000 MS Memory Limit: 65536 K
Total Submit: 43(20 users) Total Accepted: 19(18 users) Rating:  Special Judge: No
Description

夏夜,Wan带着他的妹子去郊外看星星了。

繁星满天,他们平躺在草地上数星星。

但是Wan觉得数星星太没意思。

所以他就给一些星星连线,只连结给妹子看。

一共给N颗星星连线,并且只用用水平或垂直的线连结这些星星,就像下面的图一样。

         

每颗星星最多连结4颗星星,上下左右,连结线两两不交叉,每条线只连结两颗星星。

现在开始连线了,描述信息如下:

从星星a往上连结一条长度为len1的线到达星星b

从星星c往右连结一条长度为len1的线到达星星b

……

以此类推。

 

可爱的妹子有时就会淘气的打断Wan,问星星a到星星b的曼哈顿距离是多少,Wan就停下连线,回答他妹子的问题。但并不是任何时候两颗星星都能确定它们的曼哈顿距离的,只有那些能通过连结线互通的星星才能确定。
Input

有多组测试数据,对于每组测试数据:

1行:两个分开的整数:NM;(2<=N<=400001 <= M < 50000

2..M+1行:每行为“A  X1  X2  LEN  D 或者 Q  X1  X2。”

X1X2表示两颗星星的编号。

如果是“A  X1  X2  L  D”,表示连结两颗星星X1X2LEND分别描述连结线的长度(1<=LEN<=1000),X1X2的方向(上:U,右:R,下:D,左:L)。

如果是“Q  X1  X2”,表示停下连线,询问星星X1X2的曼哈顿距离。

其中询问至少1次,最多不超过10000次。
Output

对于每组测试数据的每个询问,输出两个星星X1X2的曼哈顿距离,如果不能确定它们的曼哈顿距离,则输出“-1“。

Sample Input

7 9

A 1 6 13 R

Q 1 6

A 6 3 9 R

A 3 5 7 D

Q 1 4

A 4 1 3 U

A 2 4 20 L

A 4 7 2 D

Q 2 6

Sample Output

13

-1

10

Hint

曼哈顿距离:在(x1,y1)(x2,y2)之间的“曼哈顿距离”,就是|x1-x2|+|y1-y2|

Author
cowfork@HRBUST

路径我们可以分成两组来做,UD一组,LR一组我们只需要一个并查集数组和两个权值数组就可以搞定这个问题了。当然,我们需要做的还有方向,我们可以规定UR为两组方向的正方向,当然也可以规定LR一组做正方向。

带权并查集基础习题:哈理工oj 2240 土豪的时代:http://blog.csdn.net/mengxiang000000/article/details/50646977

AC代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
int f[1000010];
int sum[1000010];
int sum2[1000010];
int n,m;
int find(int x)
{
    if(x!=f[x])
    {
        int pre=f[x];//pre是x的一个父节点。
        f[x]=find(f[x]);//递归找祖先。
        sum[x]+=sum[pre];
        sum2[x]+=sum2[pre];
    }
    return f[x];
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)
        {
            f[i]=i;
            sum[i]=0;
            sum2[i]=0;
        }
        while(m--)
        {
            char op[2];
            scanf("%s",op);
            if(op[0]=='A')
            {
                int u,v,len;
                char fangxiang[2];
                scanf("%d%d%d%s",&u,&v,&len,fangxiang);
                int x,y;
                if(fangxiang[0]=='U')x=len,y=0;
                if(fangxiang[0]=='D')x=-len,y=0;//UD一组
                if(fangxiang[0]=='R')x=0,y=len;
                if(fangxiang[0]=='L')x=0,y=-len;//RL一组
                int V=find(v);
                int U=find(u);
                if(V!=U)
                {
                    f[U]=V;//方向都是随便规定的,只要不冲突就行、
                    sum[U]=-sum[u]+sum[v]+x;
                    sum2[U]=-sum2[u]+sum2[v]+y;
                }
            }
            if(op[0]=='Q')
            {
                int u,v;
                scanf("%d%d",&u,&v);
                if(find(u)==find(v))
                printf("%.lf\n",fabs(sum[u]-sum[v])+fabs(sum2[u]-sum2[v]));//这个就相当于求x,y的距离差加和,这里要注意的一点是fabs得到的结果是double的
                else
                {
                    printf("-1\n");
                }
            }
        }
    }
}







你可能感兴趣的:(1418,1418,哈理工oj,hrbust)