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); } } }