acwing 238. 银河英雄传说 并查集
Posted itdef
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了acwing 238. 银河英雄传说 并查集相关的知识,希望对你有一定的参考价值。
地址 https://www.acwing.com/problem/content/240/
有一个划分为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
输入样例: 4 M 2 3 C 1 2 M 2 4 C 4 2 输出样例: -1 1
当一个队列转移到另一个队列下面的时候 就合并了
可以考虑使用并查集
如
1 5 8 9 ---> 1 8 9
2 6 2
3 7 3
4 4
5
6
7
但是距离就不好统计了
我们可以再开 一个数组记录每个元素到队列的距离 合并的时候也只需要更新队列首部的距离和该队列元素数 其他元素的距离可以留到find函数递归的时候再行更新
有点类似线段树的lazy操作
比如图1中 元素4 距离队列头部1 距离为3
队列头部1距离为0 队列元素为4
元素7 距离队列5 距离为2
队列头部元素5 记录该队列size为3
合并后
更新队列元素1 size为7
更新元素5距离队列头部距离为4(也就是之前队列头部元素1记录的size)
元素 6 7 的实际距离可以在并查集find函数调用时候再计算 也就是 元素6距离队列首部距离= 元素5距离队列首部距离4+ 元素6距离原来的队首元素5的距离1
代码如下
#include <iostream> using namespace std; const int N = 31000 + 10; int fa[N], n, t, i, j, d[N], size_[N];//size就是记录个数 int get(int x) { if (x == fa[x]) return x; int root = get(fa[x]); d[x] += d[fa[x]];//往下推进 return fa[x] = root; } void merge(int x, int y) { x = get(x), y = get(y); fa[x] = y, d[x] = size_[y]; size_[y] += size_[x];//顺带记录 } int main() { scanf("%d ", &t); for (i = 1; i <= 30000; i++) fa[i] = i, size_[i] = 1; while (t--) { char ch = getchar(); scanf("%d %d ", &i, &j); if (ch == ‘M‘) merge(i, j); else { if (get(i) == get(j)) cout << abs(d[i] - d[j]) - 1; else cout << "-1"; cout << endl; } } return 0; }
以上是关于acwing 238. 银河英雄传说 并查集的主要内容,如果未能解决你的问题,请参考以下文章