POJ1962:Corporative Network【带权并查集】

<题目链接>

题目大意:

n个节点,若干次询问,I x y表示从x连一条边到y,权值为|x-y|%1000;E x表示询问x到x所指向的终点的距离。 

 解题分析:

与普通的带权并查集类似,但是要注意的是,在进行查询操作时,也要调用一下find函数,因为以前的uion操作可能将某些值改变了,所以find()操作是将这些节点全部更新一遍,得到它们的真实值。

#include <cstdio>
#include <cmath>

const int maxn=20000+100;

int father[maxn],dis[maxn];
int n;

int find(int x){
    if(father[x]==x)
        return x;
    int temp=father[x];
    father[x]=find(father[x]);
    dis[x]=dis[x]+dis[temp];      //x到根节点的距离=x到父亲的距离+父亲到根节点的距离。不能交换这句和上一句的顺序,否则dis[x]就表现不了到新根的距离了
    return father[x];
}

void Uion(int a,int b){
    int ra=find(a);
    int rb=find(b);
    if(ra!=rb){
        father[ra]=rb;
        dis[ra]=(abs(a-b)%1000-dis[a]+dis[b]);     //根据矢量,得出ra到rb的距离
    }
}

int main(){
    int t;scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            father[i]=i;
            dis[i]=0;
        }
        getchar();
        char ch;
        while(scanf("%c",&ch)){
            if(ch=='O')break;
            if(ch=='I'){
                int a,b;
                scanf("%d %d",&a,&b);
                Uion(a,b);
                getchar();
            }
            else{
                int a;
                scanf("%d",&a);
                find(a);      //注意这里,查询的时候也要压缩一下,因为uion操作会更新dis数据
                printf("%d
",dis[a]);
                getchar();
            }
        }
    }
    return 0;
}

2018-08-19

原文地址:https://www.cnblogs.com/00isok/p/9503084.html