【ACWing】238. 银河英雄传说

news/2024/11/15 0:11:57/

题目地址:

https://www.acwing.com/problem/content/240/

有一个划分为 N N N列的星际战场,各列依次编号为 1 , 2 , … , N 1,2,…,N 1,2,,N。有 N N N艘战舰,也依次编号为 1 , 2 , … , N 1,2,…,N 1,2,,N,其中第 i i i号战舰处于第 i i i列。有 T T T条指令,每条指令格式为以下两种之一:M i j,表示让第 i i i号战舰所在列的全部战舰保持原有顺序,接在第 j j j号战舰所在列的尾部。C i j,表示询问第 i i i号战舰与第 j j j号战舰当前是否处于同一列中,如果在同一列中,它们之间间隔了多少艘战舰。现在需要你编写一个程序,处理一系列的指令。

输入格式:
第一行包含整数 T T T,表示共有 T T T条指令。接下来 T T T行,每行一个指令,指令有两种形式:M i jC i j。其中 M M M C C C为大写字母表示指令类型, i i i j j j为整数,表示指令涉及的战舰编号。

输出格式:
你的程序应当依次对输入的每一条指令进行分析和处理:如果是M i j形式,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息;如果是C i j形式,你的程序要输出一行,仅包含一个整数,表示在同一列上,第 i i i号战舰与第 j j j号战舰之间布置的战舰数目,如果第 i i i号战舰与第 j j j号战舰当前不在同一列上,则输出 − 1 −1 1

数据范围:
N ≤ 30000 , T ≤ 500000 N≤30000,T≤500000 N30000,T500000

由于不仅要询问两个战舰是否同列,还需要知道两个战舰之间还有多少个战舰,所以需要用带权并查集来解决,即在维护集合的时候同时维护点与点之间的边权。我们可以维护并查集的每个树根为每列的最上面的那个战舰编号,然后再维护两个信息,一个是 s [ i ] s[i] s[i],表示 i i i所在集合的元素个数(只对树根有效),另一个是 d [ i ] d[i] d[i],表示 i i i到其父亲的距离(这里的“距离”指的是之间隔了的战舰数加 1 1 1,应答询问的时候是利用前缀和思想来求的。如果 i i i本身就是树根,则 d [ i ] = 0 d[i]=0 d[i]=0,如果是树根的孩子,并且 i i i号战舰紧挨着树根,则 d [ i ] = 1 d[i]=1 d[i]=1,以此类推)。维护 s s s是容易的,最重要的是怎么维护 d d d。首先在做合并集合的操作的时候,例如我们要将 x x x所在集合并到 y y y里,那么先找到两者的树根,即 p x p_x px p y p_y py,由于合并完之后 p x p_x px就会接到 p y p_y py下面,所以 p x p_x px与树根的距离就会被更新为 s [ p y ] s[p_y] s[py](类比两列战舰的合并,合并后战舰 p x p_x px会挂到 p y p_y py所在列的下面,当然距离就是 s [ p y ] s[p_y] s[py]了)。但是对于 p x p_x px所在集合的其余节点该如何处理呢?由于find函数的路径压缩优化,我们只需要在find里处理即可,在union的时候是不需要特别处理的(因为在询问的时候,会首先执行find,而find完之后由于路径压缩,所有节点都直接指向树根了)。在执行find(u)的时候,处理的方法是采用后序遍历,先递归地找到树根(此时 u u u节点的父亲 p u p_u pu已经连到树根上去了,并且 d [ p u ] d[p_u] d[pu]也算好了),然后将 d [ u ] d[u] d[u]累加其父亲的 d d d值即可,因为此时 d [ u ] d[u] d[u] u u u与父亲 p u p_u pu的距离,然后再累加 p u p_u pu到新树根的距离就行了。代码如下:

#include <iostream>
#include <cstring>
using namespace std;const int N = 30010;
int m;
// sz[i]存i所在集合的元素个数(只对树根有效),d[i]存i与其父亲的距离
int p[N], sz[N], d[N];int find(int x) {if (p[x] == x) return x;int root = find(p[x]);d[x] += d[p[x]];return p[x] = root;
}void merge(int x, int y) {int px = find(x), py = find(y);p[px] = py, d[px] = sz[py];sz[py] += sz[px];
}int main() {for (int i = 1; i < N; i++) p[i] = i, sz[i] = 1;scanf("%d", &m);while (m--) {char op[2];int a, b;scanf("%s%d%d", op, &a, &b);if (op[0] == 'M') {merge(a, b);} else {if (a == b) puts("0");int pa = find(a), pb = find(b);if (pa != pb) puts("-1");else printf("%d\n", abs(d[a]- d[b]) - 1);}}return 0;
}

时间复杂度 O ( N + T log ⁡ ∗ N ) O(N+T\log ^*N) O(N+TlogN),每次询问几乎可以看成是常数应答,空间 O ( N ) O(N) O(N)


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

相关文章

六边形战士

代码 效果如下

猎人、猎狗和公司

西方企业制度和经济制度的由来 至理名言&#xff1a; 干活的总是拿得少的&#xff0c;拿得多的都是不干活的——《人力资源管理》&#xff08;批注&#xff1a;此话全有道理吗&#xff1f;不是&#xff01;&#xff09; 也许有人看过&#xff0c;但没关系&#xff0c;的确有意思…

盘点五种最常见加密算法!

大家好&#xff0c;我是Martin。 今天&#xff0c;就给大家来盘点一下最常见的5种加密算法。 大家平时的工作中&#xff0c;可能也在很多地方用到了加密、解密&#xff0c;比如&#xff1a; 用户的密码不能明文存储&#xff0c;要存储加密后的密文 用户的银行卡号、身份证号…

Unreal 5 实现丧尸追逐攻击功能

要实现让丧尸能够智能的追逐玩家&#xff0c;我们需要用到ue封装的ai行为树来实现。基础相关的请查看&#xff1a;Unreal Engine 5.1 AI行为树基础入门&#xff0c;来学习一下如何使用ai行为树来实现一个简单的追逐功能。这一篇就是基于这个基础上进行了优化&#xff0c;实现了…

Modbus协议基于modscan 的设备数据收发过程模拟

Modbus协议基于modscan 的设备数据收发过程模拟 一、基本介绍二、工具使用说明2.1 Modsim32的使用 - 模拟从设备 - 生成设备数据2.1.1 新建虚拟设备 - modsim文件2.1.2 打开虚拟设备 - modsim文件2.1.3 连接设置2.1.3.1 modbus /tcp连接2.1.3.2 COM连接 2.1.4 配置 - 设置数据自…

不会点爬虫技术写代码真没意思,Java 爬虫利器 Jsoup 详解

Jsoup的概述 Jsoup是一款Java语言开发的HTML解析器&#xff0c;用于解析HTML文档以及对HTML文档进行操作&#xff0c;处理等。它提供了类似于jQuery的DOM操作方法&#xff0c;以及用于HTML元素遍历、迭代、查询以及修改等操作的API&#xff0c;同时还支持CSS选择器和正则表达式…

oracle 查所有表空间\用户\表\视图\序列号\同义词 判断表是否有数据

–查所有表空间 select tablespace_name, sum(bytes)/1024/1024 from dba_data_files group by tablespace_name; –查所有用户 select * from all_users order by username; –查当前用户下所有表 表名 表说明 字段说明 select * from user_tab_comments where table_type‘TA…

她98年的,我玩不过她...┭┮﹏┭┮

现在的小年轻真的卷得过分了。前段时间我们公司来了个98年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…