洛谷——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; }
博主蒟蒻,若有出错的地方,敬请指出。
如有侵犯您版权的地方,请快速联系我,我会撤回本博文。