P1196 银河英雄传说

  这题真的很经典,我WA了三次,最后一次才AC……

  因为这道题是很有技术含量的,能自己写出来真的很厉害(不是在夸自己)。如果只是粗略的去看题解或者抄题解(倒是可以用来蒙骗自己),那这道题就失去意义了。下面的代码,每一句话,都是值得深刻推敲的。

  举几个例子:

int find(int x)
{
    if(x==par[x])
    return x;
    int p=find(par[x]);
    dp[x]+=dp[par[x]];
    return par[x]=p;
}

  这里就不能直接写par [ x ] = find ( par [ x ] ),后面写return par [ x ] 。(为什么想过么?)

  而且粗略地想:深度不应该是父亲 + 1 吗?而且每一次都把深度加一遍,不会有错吗?

  如果你这么想,那么首先你并没有掌握并查集的本质和基础的定义,需要再踏踏实实搞好基础;如果你根本就没想到这一点,而是直接欺骗自己感性地理解,那么你只是背了一个最普通的板子,并且和没学过没有区别,不可能独立敲出这道题。

  而这只是一部分,要不我也不会说这道题经典……

  太晚了,不解释为什么了,如果你感兴趣,可以来窗边第一号机位。

  代码贴上:(可能没有题解写得好)

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
#define maxn 3000005
int n,dp[maxn],par[maxn],am[maxn];
int find(int x)
{
    if(x==par[x])
    return x;
    int p=find(par[x]);
    dp[x]+=dp[par[x]];
    return par[x]=p;
}
void merge(int x,int y)
{
    int fx=find(x),fy=find(y);
    dp[fx]+=am[fy];
    par[fx]=fy;
    am[fy]+=am[fx];
    am[fx]=0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    par[i]=i,am[i]=1; 
    for(int i=1;i<=n;i++)
    {
        char s;
        int x,y;
        cin>>s;
        scanf("%d%d",&x,&y);
        if(s=='M')
        merge(x,y);
        else
        {
            int fx=find(x),fy=find(y);
            if(fx!=fy)
            {
                printf("-1\n");
                continue;
            }
            else
                printf("%d\n",abs(dp[y]-dp[x])-1);
        }
    }
}

 

posted @ 2018-12-19 00:55  paopo  阅读(197)  评论(0编辑  收藏  举报