[洛谷P1196]银河英雄传说

题目大意:有30000个船,第i个船在第i列,两个操作,M:把第i列的船整体拼到第j列船后,C:求第i和第j个船之间的船的个数
题解:可以想到用并查集,在基础的并查集上增加路径,用num数组存第i个船到队首的距离,用len存这一列的船的个数。问题主要在路径压缩上维护num数组上。可以在find的过程中,每改变f[x]的时候把num[i]加上num[f[i]],就可以维护了。
卡点:在num数组初始赋值为了1,导致每find一遍,所搜索的值就加了1(根节点)。没看清要求求的是中间船的个数,写成了包括两头的。在求出答案时,误把num[i]-num[j]写成了num[find[i]]-num[find[j]]

 

C++ Code:

#include<cstdio>
#include<cstdio>
const int maxn=30010;
int n,f[maxn],num[maxn],len[maxn];
char ch[5];
int find(int x){
    if (x==f[x])return x;
    int xx=find(f[x]);
    num[x]+=num[f[x]];
    return f[x]=xx;
}
int abs(int a){return a>0?a:-a;}
int main(){
    scanf("%d\n",&n);
    for (int i=1;i<maxn;i++)f[i]=i,len[i]=1;
    while (n--){
        int a,b;
        scanf("%s%d%d",ch,&a,&b);
        if (ch[0]=='M'){
            int x=find(a),y=find(b);
            if (x==y)continue;
            num[x]=len[y];
            len[y]+=len[x];
            f[x]=y;
        }else{
            int x=find(a),y=find(b);
            if (x!=y){
                puts("-1");
                continue;
            }
            printf("%d\n",abs(num[a]-num[b])-1);
        }
    }
    return 0;
}

 

posted @ 2017-12-10 15:54  Memory_of_winter  阅读(178)  评论(0编辑  收藏  举报