洛谷 P1196 银河英雄传说 (带权并查集)

news/2024/12/5 11:52:57/

题目描述:

题目传送门


解题思路:

根据数据范围以及题目中提到的合并等操作可以联想用并查集求解。
但是仔细想想,普通并查集只能判断某元素是否为统一集合的联通性问题,而题目中提到了“战舰数量”等权值性的问题,这种时候我们就要对并查集进行一些改变,成为可以处理权值的带权并查集

  • 带权并查集

必须要了解的前置知识是并查集(废话),百度食用更佳。

带权并查集其实和普通并查集没有本质的区别,仅仅只是需要在路径压缩或合并集合的时候维护或更新节点与父节点的边权关系以及维护该集合内元素个数。

f a x fa_{x} fax 表示从 x x x x x x 的父节点的边权, d i s x dis_x disx 表示从 x x x 到达 f a x fa_x fax 的边权, c n t x cnt_x cntx 表示为元素 x x x 所在的集合的元素个数。

  1. 考虑合并集合 a a a b b b ,我们可以让集合 a a a 的根节点与集合 b b b 的根节点相连,这样 a a a 就成为了 b b b 的一颗子树。可以的之,连接后 a a a 子树的深度肯定是位于原本 b b b 所有子树的下方,也就是说, a a a 的根节点 x x x 到大 b b b 的根节点 y y y 的距离是原本 b b b 子树的元素个数,也就是说 d i s x = c n t y dis_x=cnt_y disx=cnty。也很容易理解,由于加上了子树 a a a,那么 b b b 的元素个数为 c n t x + c n t y cnt_x+cnt_y cntx+cnty
  2. 考虑路径压缩操作,所有节点的父亲都为跟,也就是说我们要维护使得所有节点与根的边权不变。操作后, f a x fa_x fax 节点的父亲变为集合的根,也就是说 f a f a x fa_{fa_x} fafax 是这个集合的跟,那么 x x x 点到达根的距离为: d i s x = d i s x + d i s f a x dis_x=dis_x+dis_{fa_x} disx=disx+disfax。这句话的解析其实就是该节点到达父节点的距离,再加上父节点到达根的距离,即为该节点到达根的距离。

带权并查集的查询:

int find(int x)
{if(fa[x]==x) return x;int t=find(fa[x]);  //必须要有这么一赋值步骤,因为复制中find函数已经运行过一次了,此时 fa[fa[x]]为根节点,与分析相符;否则 fa[fa[x]]未经过改变,不为根节点,与分析不符dis[x]+=dis[fa[x]];  //更新当前点到根节点的距离fa[x]=t;return fa[x];
}

关于赋值操作的必要性请看此贴

合并集合操作:

void join(int x,int y)
{int a=find(x),b=find(y);fa[a]=b;dis[a]=cnt[b];  //更新根节点之间的距离cnt[b]+=cnt[a];  //更新集合元素个数cnt[a]=cnt[b];
}

知道了带权并查集的思想,这道题就不难解除。


CODE:

#include <iostream>
#include <cmath>
using namespace std;
int n;
int fa[50010],dis[50010]={0},cnt[50010];
int find(int x)
{if(fa[x]==x) return x;int t=find(fa[x]); dis[x]+=dis[fa[x]];fa[x]=t;return fa[x];
}
void join(int x,int y)
{int a=find(x),b=find(y);fa[a]=b;dis[a]=cnt[b];cnt[b]+=cnt[a];cnt[a]=cnt[b];
}
int main()
{std::ios::sync_with_stdio(false);  //关闭输入输出同步流cin>>n;char pos;int a,b;for(int i=1;i<=30000;i++) fa[i]=i,cnt[i]=1;for(int i=1;i<=n;i++){cin>>pos>>a>>b;if(pos=='M'){if(find(a)!=find(b))join(a,b);}if(pos=='C'){if(find(a)!=find(b)) cout<<-1<<endl;else cout<<abs(dis[a]-dis[b])-1<<endl;}}return 0;
} 

http://www.ppmy.cn/news/578365.html

相关文章

P1196 [NOI2002] 银河英雄传说 带权并查集

[NOI2002] 银河英雄传说 题目背景 公元 5801 5801 5801 年&#xff0c;地球居民迁至金牛座 α \alpha α 第二行星&#xff0c;在那里发表银河联邦创立宣言&#xff0c;同年改元为宇宙历元年&#xff0c;并开始向银河系深处拓展。 宇宙历 799 799 799 年&#xff0c;银河…

「洛谷」P1196 银河英雄传说

P1196 银河英雄传说 https://www.luogu.com.cn/problem/P1196 题目描述 杨威利擅长排兵布阵&#xff0c;巧妙运用各种战术屡次以少胜多&#xff0c;难免恣生骄气。在这次决战中&#xff0c;他将巴米利恩星域战场划分成 30000 列&#xff0c;每列依次编号为 1 , 2 , … , 3000…

银河英雄传说 题解

题目大意 杨威利擅长排兵布阵&#xff0c;巧妙运用各种战术屡次以少胜多&#xff0c;难免恣生骄气。在这次决战中&#xff0c;他将巴米利恩星域战场划分成 30000列&#xff0c;每列依次编号为 1,2,…,30000。之后&#xff0c;他把自己的战舰也依次编号为1,2,…,30000&#xff…

[并查集]银河英雄传说

Description 公元五八○一年&#xff0c;地球居民迁移至金牛座α第二行星&#xff0c;在那里发表银河联邦创立宣言&#xff0c;同年改元为宇宙历元年&#xff0c;并开始向银河系深处拓展。 宇宙历七九九年&#xff0c;银河系的两大军事集团在巴米利恩星域爆发战争。泰山压顶集…

AcWing238. 银河英雄传说

AcWing238. 银河英雄传说 有一个划分为N列的星际战场&#xff0c;各列依次编号为1,2,…,N。 有N艘战舰&#xff0c;也依次编号为1,2,…,N,其中第i号战舰处于第i列。 有T条指令&#xff0c;每条指令格式为以下两种之一&#xff1a; 1、M i j&#xff0c;表示让第i号战舰所在…

【并查集】银河英雄传说

题目描述 公元5801年&#xff0c;地球居民迁移至金牛座α第二行星&#xff0c;在那里发表银河联邦创立宣言&#xff0c;同年改元为宇宙历元年&#xff0c;并开始向银河系深处拓展。 宇宙历799年&#xff0c;银河系的两大军事集团在巴米利恩星域爆发战争。泰山压顶集团派宇宙舰…

银河英雄传说(并查集)

问题描述 有一个划分为N列的星际战场&#xff0c;各列依次编号为1,2,…,N。 有N艘战舰&#xff0c;也依次编号为1,2,…,N,其中第i号战舰处于第i列。 有T条指令&#xff0c;每条指令格式为以下两种之一&#xff1a; 1、M i j&#xff0c;表示让第i号战舰所在列的全部战舰保持…

银河英雄传说旗舰名称考证—同盟军

同盟军部分&#xff1a;      宇宙舰队总司令罗波斯元帅旗舰   アイアース   Aias或Ajax   艾亚斯   荷马史诗《伊利亚特》中俄琉斯之子&#xff0c;特洛亚战争中的希腊英雄。他的勇猛仅次于阿喀琉斯&#xff0c;在诸英雄中名列第二。      第二舰队派特…