洛谷——P1196 [NOI2002]银河英雄传说

P1196 [NOI2002]银河英雄传说

 

题目大意:

给你一个序列,支持两种操作:

合并指令为$M_{i,j}$j,含义为第i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。

$C_{i,j}$该指令意思是,询问电脑,杨威利的第ii号战舰与第jj号战舰当前是否在同一列中,如果在同一列中,那么它们之间布置有多少战舰。

 

据说是带权并查集,其实就是多维护了几个变量而已,

fa[x]依旧表示x的父亲,front[x]表示x与x队头之间的距离,num[x]表示以x为队头的队列中战舰的数量

重点在于如何维护front

显然在合并过程中front和num是在改变的

考虑如果将x与y合并,其队头分别为fx和fy

首先更新fx的父亲,其次更新front[fx],更新的是放在队尾的队头,front[fx]+=num[fy]

再更新fy的队列战舰数量,num[fy]+=num[fx],num[fx]=0

 

这个过程中,显然只有处在对头的front被更新了,那么处在队列其他位置的front如何更新呢

这个就需要在find操作中实现

front[x]+=front[fa[x]];

 

#include<bits/stdc++.h>

#define N 500000
using namespace std;

int T,fa[N],num[N],front[N];
//front[x]表示x与x队头之间的距离 
//num[x]表示以x为队头的队列长度 
int find(int x){
    if(fa[x]==x) return x;
    int f=find(fa[x]);
    front[x]+=front[fa[x]];
    return fa[x]=f;
}

int main()
{
    scanf("%d",&T);
    for(int i=1;i<N;i++) fa[i]=i,num[i]=1;
    while(T--){
        char x;
        cin>>x;
        int i,j;
        scanf("%d%d",&i,&j);
        int fx=find(i),fy=find(j);
        if(x=='C'){
            if(fx!=fy) printf("-1\n");
            else printf("%d\n",abs(front[i]-front[j])-1);
        }else {
            fa[fx]=fy;
            front[fx]+=num[fy];//更新距离 
            num[fy]+=num[fx];//更新队列长度 
            num[fx]=0;//0
        }
    }
    return 0;
}

 

posted @ 2018-09-10 16:59  清风我已逝  阅读(171)  评论(0编辑  收藏  举报