HRBUST 1418 并查集偏移

来源:互联网 发布:淘宝手机软件 编辑:程序博客网 时间:2024/05/16 06:28

题意:给出一些点,这些点可以通过线段连接,如果两个点能通过线段直接或者间接的连在了一起,那么他们之间可以确定一个曼哈顿距离

这个距离为  |x1-x2|+|y1-y2|,如果不能连,为-1

给出N个点 ,M 次操作

然后M行,每行一个操作,一共有两种

_1   A st ed len to  ,A代表操作类型为连接,st  ed 是两个点的标号,len代表一条线段长度,to 代表方向(上下左右,UDLR)

意思就是从st 引一条to 方向的线段连到了ed

_2  Q st  ed  ,Q 代表操作类型 为 询问,询问标号为st 和ed  的两个点的曼哈顿距离,如果不存在就输出-1


判断能不能通过线段连在一起,很自然能想到是并查集,点与点之间的关系都是相对的,只要维护并查集中的偏移量(子节点相对于根节点的上下偏移量和左右偏移量)

之前的公式依然适用,简单说就是,

get 操作偏移量 就是 sum[x]=sum[x]+sum[f[x]]

并操作    sum[f2]=-sum[f2]+sum[f1]+t,t就是相对关系,也就是长度/性别/帮派之类

需要注意的就是对于每个方向的操作,对应方向上要+相对关系,而另外的方向只要 公式的前面两个量~,因为另外一个方向没有相对关系或者说保持和之前相同的相对关系

最后求出两个点相对根节点的某个方向的相对距离一减,然后求绝对值就可以了~

#include<stdio.h>#include<string.h>int f[40000+5];int lr[40000+5];int ud[40000+5];int abs(int a){    if(a>=0)return a;    else return -a;}int get(int x){    if(f[x]!=x){        int t=f[x];        f[x]=get(f[x]);        lr[x]=lr[x]+lr[t];        ud[x]=ud[x]+ud[t];    }    return f[x];}void bing(int st,int ed,int len,char to[15]){    int f1=get(st),f2=get(ed);    if(f1!=f2){        f[f2]=f1;        if(to[0]=='L'){        lr[f2]= -lr[ed]-len+lr[st];        ud[f2]= -ud[ed]+ud[st];        }        if(to[0]=='R'){        lr[f2]= -lr[ed]+len+lr[st];        ud[f2]= -ud[ed]+ud[st];        }        if(to[0]=='U'){        ud[f2]= -ud[ed]+len+ud[st];        lr[f2]= -lr[ed]+lr[st];        }        if(to[0]=='D'){        ud[f2]= -ud[ed]-len+ud[st];        lr[f2]= -lr[ed]+lr[st];        }    }}int main(){    int n,m,st,ed,len;    char op[15],to[15];    while(scanf("%d %d",&n,&m)!=EOF){        for(int i=0;i<=n;i++){            f[i]=i,lr[i]=ud[i]=0;        }        while(m--){        scanf("%s",&op);        if(op[0]=='Q'){            scanf("%d %d",&st,&ed);            if(get(st)==get(ed)){                printf("%d\n",abs(lr[st]-lr[ed])+abs(ud[st]-ud[ed]));            }            else printf("-1\n");        }else{            scanf("%d %d %d %s",&st,&ed,&len,&to);            bing(st,ed,len,to);        }        }    }return 0;}





原创粉丝点击