ACWing 238 银河英雄传说
最近带权并查集这块比较薄弱,直接看食物链看不懂,就老实一步步来了。
有一个划分为N列的星际战场,各列依次编号为1,2,…,N。
有N艘战舰,也依次编号为1,2,…,N,其中第i号战舰处于第i列。
有T条指令,每条指令格式为以下两种之一:
1、M i j,表示让第i号战舰所在列的全部战舰保持原有顺序,接在第j号战舰所在列的尾部。
2、C i j,表示询问第i号战舰与第j号战舰当前是否处于同一列中,如果在同一列中,它们之间间隔了多少艘战舰。
现在需要你编写一个程序,处理一系列的指令。
输入格式
第一行包含整数T,表示共有T条指令。
接下来T行,每行一个指令,指令有两种形式:M i j或C i j。
其中M和C为大写字母表示指令类型,i和j为整数,表示指令涉及的战舰编号。
输出格式
你的程序应当依次对输入的每一条指令进行分析和处理:
如果是M i j形式,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息;
如果是C i j形式,你的程序要输出一行,仅包含一个整数,表示在同一列上,第i号战舰与第j号战舰之间布置的战舰数目,如果第i号战舰与第j号战舰当前不在同一列上,则输出-1。
数据范围
N≤30000,T≤500000
原题链接:https://www.acwing.com/problem/content/240/
由于直接维护每对战舰之间的距离的时间复杂度非常大,所以我们考虑维护每个战舰到队头的距离,这样如果两只战舰在同一列上且i != j,那么我们就直接通过两个战舰各自到队头的距离相减得到答案,所以我们的查询函数可以这么写:
int Query(int a, int b)
{
if(a == b) return ;
if(issame(a, b)) return abs(d[a] - d[b]) - ; return -;
}
既然查询总是涉及子节点跟祖宗节点产生直接联系,那么我们可以考虑使用带权并查集来维护这个d[i],这个d[i]代表自己到父节点的距离,但是由于并查集的路径压缩,最终每个子节点的父节点都会变成他们的祖宗,也就是说这个d[i]就变成了子节点到祖宗的距离。

我们知道,对于祖宗来说,它到自己的距离是0,所以祖宗的d[i]是0,同时我们也能推出初始化的d[]数组也应该全部是0
那么在一棵树上的d[x]的更新跟路径压缩怎么去弄呢?
假设目前这颗树是长这样子的

那么路径压缩后应该长这样子

这里边发生的变化,其实就是3号节点接到了1号节点上,并且因为2号节点到1号节点的距离为1,然后3号节点到2号节点距离也是1,那么我们可以计算出3号节点到1号节点距离应该是d[2] + d[3] = 2。
达成这个目的的具体步骤也不难,就是先顺着3号节点用递归方式摸到2号节点再摸到1号节点,然后又从一号节点顺着那根线回来把距离都加到手

所以,我们的查找祖宗+路径压缩的代码就如下
int find(int x)
{
if(x == fa[x]) return x; //是祖宗就直接返回自己 int root = find(fa[x]); //找到根节点
d[x] += d[fa[x]]; //递归把距离一路加回来
fa[x] = root; //把子节点接到祖宗节点上
return root;
}
但是有个问题,两棵树合并时,也就是一个队插到另一个队的后面时,这个d怎么去更新才合适呢?

容易知道,当一个队插到另一个队的后面时,这个队的队头就排到了另一个队的队尾,那么我们就推算出这个队头到另一个队头的距离数值上等于另一个队的长度
因为涉及到队的长度,所以我们还要再引入一个信息,就是队的长度L
因为队的长度只有在两个不同的队合并时才会发生变化,所以这个L[]还是十分好维护的,就是两队长度相加即可
所以我们合并的时候,先更新祖宗d[x]再更新L[]就能达成任务了
void merge(int a, int b)
{
if(!issame(a, b)){
int root_a, root_b;
root_a = find(a);
root_b = find(b);
d[root_a] = l[root_b];
l[root_b] += l[root_a];
fa[root_a] = root_b;
}
}
查找、路径压缩以及合并,并查集的这些功能就水到渠成了
之后用就行
贴上AC代码
#include<iostream>
#include<algorithm>
using namespace std; const int Maxn = 3e4 + ;
int fa[Maxn];
int l[Maxn];
int d[Maxn]; int find(int x)
{
if(x == fa[x]) return x; //是祖宗就直接返回自己 int root = find(fa[x]); //找到根节点
d[x] += d[fa[x]]; //递归把距离一路加回来
fa[x] = root; //把子节点接到祖宗节点上
return root;
} bool issame(int a, int b)
{
return find(a) == find(b);
} void merge(int a, int b)
{
if(!issame(a, b)){
int root_a, root_b;
root_a = find(a);
root_b = find(b);
d[root_a] = l[root_b];
l[root_b] += l[root_a];
fa[root_a] = root_b;
}
} int Query(int a, int b)
{
if(a == b) return ;
if(issame(a, b)) return abs(d[a] - d[b]) - ; return -;
} int main()
{
for(int i=; i<Maxn ;i++){
fa[i] = i;
l[i] = ;
} int m;
cin>>m;
while(m--){
char op;
int i, j;
cin>>op>>i>>j;
if(op == 'M') merge(i, j);
else cout<<Query(i, j)<<endl;
} return ;
}
ACWing 238 银河英雄传说的更多相关文章
- NOI2002_ Galaxy银河英雄传说86
NOI2002_ Galaxy银河英雄传说86 公元五八○一年,地球居民迁移至金牛座α第二行星,:宇宙历七九九年,银河系的两大军事集团在巴米利恩星:杨威利擅长排兵布阵,巧妙运用各种战术屡次以少 ...
- P4847 银河英雄传说V2 题解(Splay)
题目链接 P4847 银河英雄传说V2 解题思路 我天哪!!!\(splay\)在\(rotate\)的时候先\(upd(y)\)再\(upd(x)\)!!以后不能再因为这个\(WA\)一晚上了!!! ...
- codevs1540 银河英雄传说
描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山压顶集 ...
- NOI2002 洛谷 P1196 银河英雄传说
神奇的并查集问题 题目描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦 创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩 ...
- NOI2002 银河英雄传说
P1196 银河英雄传说 367通过 1.1K提交 题目提供者该用户不存在 标签并查集NOI系列2001(或之前) 难度提高+/省选- 提交该题 讨论 题解 记录 最新讨论 莱因哈特什么鬼? 私人代码 ...
- codevs 1540 银河英雄传说
题目描述 Description 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米 ...
- 数据结构(并查集):COGS 260. [NOI2002] 银河英雄传说
260. [NOI2002] 银河英雄传说 ★★☆ 输入文件:galaxy.in 输出文件:galaxy.out 简单对比时间限制:5 s 内存限制:128 MB [问题描述] 公元五 ...
- CH4101 银河英雄传说
题意 4101 银河英雄传说 0x40「数据结构进阶」例题 描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七 ...
- codevs 1540 1540 银河英雄传说
1540 银河英雄传说 题目描述 Description 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银 ...
随机推荐
- 37.Python自定义过滤器
自定义模板过滤器 1.首先在某个app中,创建一个python包,叫做"templatetags",注意,这个包的名字一定要是"templatetags",否者 ...
- 2020qbxt游记
csp-s 突破 ----------------------------------------- 1-15 下午才走,这实在是太恶心了.然而因为感冒,当众大佬们都在上学的时候,我在家里睡觉. 2: ...
- comTest.json文件中内容,被NewsList.vue文件引入
本文目标:就是把扩散名为.json文件中数据,传递给NewsList.vue文件.主要通过导出,并传递给data(){}变紧 新建文件名为:commTest.json { "schoolNa ...
- java 相关书籍介绍
自己做开发也有两年多了吧,其中也关注过许多大牛的博客,买过许多的书看. 自己也是个比较爱阅读的人,从小的时候被老爸逼着每次寒暑假看书,到后来慢慢长大爱上了阅读,习惯了看书. 农村的小孩吗,那时候又不像 ...
- 《Javascript DOM编程艺术》学习笔记 第1-6章
第1章 Javascript简史 Javascript是Netspace公司与Sun公司合作开发的,Javascript 1.0版于1995年推出. 为与微软公司竞争,Netspace公司和Sun公司 ...
- 吴裕雄--天生自然 python开发学习笔记:解决No module named 'mpl_toolkits.basemap'问题
. 下载: basemap-1.1.0-cp36-cp36m-win_amd64.whl和pyproj-1.9.5.1-cp36-cp36m-win_amd64.whl这两个文件 先运行: 再运行:
- CSS相对定位与绝对定位
1.相对定位 Position : relative ; 特点: 1 如果没有定位偏移量,对元素本身没有任何影响: 2 不使元素脱离文档流,空间是会被保留: 3 不影响其他元素布局: 4 left.t ...
- React函数式组件使用Ref
目录: 简介 useRef forwardRef useImperativeHandle 回调Ref 简介 大家都知道React中的ref属性可以帮助我们获取子组件的实例或者Dom对象,进而对子组件进 ...
- R 拼接结果展示
学长教的拼接结果展示 哇,R 简直太有魅力了! 晚一点补充
- [Java]对double变量进行四舍五入,并保留小数点后位数
1.功能 将double类型变量进行四舍五入,并保留小数点后位数 2.代码 import java.math.BigDecimal; import java.math.RoundingMode; im ...