zoukankan      html  css  js  c++  java
  • 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。

    数据范围

    N30000,T500000

    输入样例:
    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;
    }
    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    form表单回车提交
    Mac os x下配置nginx + php
    Mac下git命令自动补全
    关于javascript中的操作符&&和||的最终返回值
    ARM 裸机程序学习 01 点亮LED
    LINUX SHELL 中 2>&1 重定向的问题
    项目经理到底关心项目的什么?——有关外包项目成本的计算
    ARM 裸机程序学习 03 发送SOS信号(汇编 + C)
    ARM 裸机程序学习 02 按响BEEP
    备忘录 Linux及其内核杂项知识
  • 原文地址:https://www.cnblogs.com/itdef/p/12109611.html
Copyright © 2011-2022 走看看