【NOI2002T1】银河英雄传说-并查集
题目大意:有30000艘战舰依次排成30000列,以1~30000编号,有2种操作:1.M i j:将i号战舰所在的列作为一个整体接到j号战舰所在列的尾部。2.C i j:如果i号战舰和j号战舰在同一列,询问它们之间有多少艘战舰,否则输出-1。根据询问给出正确的答案。
做法:用head[i]记录i号战舰所在列的最前端的战舰序号,len[i]记录以i号战舰为最前端的列的长度,dist[i]记录i号战舰到它所在列的最前端的战舰的距离。M操作实际上就是合并操作,在合并时注意维护这几个值。x,y间的战舰数量就是abs(dist[x]-dist[y])-1。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
long t,dist[30010]={0},head[30010]={0},len[30010]={0};
char c;
long find(long x)
{
long r=x,i,j,next;
while(head[r]!=r) r=head[r];
i=x;
while(i!=r)
{
next=head[i];
head[i]=r;
j=next;
while(j!=r)
{
dist[i]+=dist[j];
j=head[j];
}
i=next;
}
return r;
}
void merge(long a,long b)
{
long fa=find(a),fb=find(b);
head[fa]=fb;
dist[fa]+=len[fb];
len[fb]+=len[fa];
}
int main()
{
scanf("%ld\n",&t);
for(int i=1;i<=30000;i++)
{
head[i]=i;
len[i]=1;
dist[i]=0;
}
for(int i=1;i<=t;i++)
{
long x,y;
scanf("%c %ld %ld\n",&c,&x,&y);
if (c=='M') merge(x,y);
if (c=='C')
{
long fx=find(x),fy=find(y);
if (fx!=fy) printf("-1\n");
else printf("%ld\n",abs(dist[x]-dist[y])-1);
}
}
return 0;
}