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


posted @ 2016-08-12 09:41  Maxwei_wzj  阅读(134)  评论(0编辑  收藏  举报