P1196 [NOI2002] 银河英雄传说
P1196 [NOI2002] 银河英雄传说
题目简述
- 
M i j:\(i\) 和 \(j\) 是两个整数(\(1 \le i,j \le 30000\)),将 \(i\) 和 \(j\) 合并
- 
C i j:\(i\) 和 \(j\) 是两个整数(\(1 \le i,j \le 30000\)),询问 \(i\) 和 \(j\) 是否在同一列,若是输出 \(i\) 和 \(j\) 之间距离,不是则输出 \(-1\)。
思路
非常经典的一道并查集题目,很好地加深对并查集的理解,因为正常操作下并查集的 \(fa[i]\) 都只是存了祖先,而中间的路径都被压缩了,所以在这题可以通过递归实现对祖先距离的不断更新依次来达到对中间的一个记录过程
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int fa[N],dis[N],num[N];//num[i]以i为开头的队列长度,dis[i]i距离i所在队列开头的长度
int get_fa(int x){
  if(x==fa[x])return x;
  int fx=get_fa(fa[x]);
  dis[x]+=dis[fa[x]];
  return fa[x]=fx;
}
void Merge(int x,int y){
  int fx=get_fa(x),fy=get_fa(y);
  fa[fx]=fy;
  dis[fx]+=num[fy];
  num[fy]+=num[fx];
  num[fx]=0;
  return ;
}
int main(){
  freopen("1196.in","r",stdin);
  freopen("1196.out","w",stdout);
  int t;
  cin>>t;
  for(int i=1;i<=3e5;i++){
    fa[i]=i;
    num[i]=1;
    dis[i]=0;
  }
  while(t--){
    char op;
    cin>>op;
    switch(op){
      case 'M':{
        int x,y;
        cin>>x>>y;
        Merge(x,y);
        break;
      }
      case 'C':{
        int x,y;
        cin>>x>>y;
        int fx=get_fa(x),fy=get_fa(y);
        if(fx!=fy)puts("-1");
        else cout<<abs(dis[x]-dis[y])-1<<endl;
        break;
      }
    }
  }
  //cout<<dis[2]<<' '<<dis[4]<<endl;
  return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号