当前位置:首页 > 比赛题解 > 2002年NOI银河英雄传说(洛谷P1196):带权并查集实战

2002年NOI银河英雄传说(洛谷P1196):带权并查集实战

20小时前比赛题解47

截图未命名.jpg 2002年NOI银河英雄传说(洛谷P1196):带权并查集实战 带权并查集 NOI真题 并查集 队列 洛谷题解 第1张

一、问题背景

题目模拟了银河战舰的队列管理,需要处理两种操作:合并战舰队列和查询战舰间距离。这是一个典型的并查集应用问题,但需要额外维护距离信息。

二、完整代码解析(含详细注释)

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

const int MAXN = 30010;  // 最大战舰数量

// 三个核心数组:
int parent[MAXN];  // 记录每个战舰的父节点
int dist[MAXN];    // 记录每个战舰到父节点的距离
int size[MAXN];    // 记录每个集合的大小(队列长度)

// 初始化并查集
void init() {
    for (int i = 1; i < MAXN; i++) {
        parent[i] = i;  // 初始时每个战舰自成一队
        dist[i] = 0;    // 到自己的距离为0
        size[i] = 1;    // 队列大小为1
    }
}

// 查找根节点,同时路径压缩并更新距离
int find(int x) {
    if (parent[x] != x) {
        int root = find(parent[x]);  // 递归找根
        dist[x] += dist[parent[x]];  // 关键:累加距离(路径压缩时维护距离)
        parent[x] = root;            // 路径压缩
    }
    return parent[x];
}

// 合并两个集合(将x所在队列接到y所在队列末尾)
void merge(int x, int y) {
    int rootX = find(x);
    int rootY = find(y);
    if (rootX != rootY) {
        parent[rootX] = rootY;       // 将x的根节点连接到y的根节点
        dist[rootX] = size[rootY];   // x根节点到新根的距离是y队列原长度
        size[rootY] += size[rootX];  // 更新新队列的总长度
    }
}

int main() {
    ios::sync_with_stdio(false);  // 加速输入输出
    cin.tie(nullptr);
    
    init();  // 初始化并查集
    
    int T;   // 指令数量
    cin >> T;
    
    while (T--) {
        char op;  // 指令类型
        int i, j;
        cin >> op >> i >> j;
        
        if (op == 'M') {
            merge(i, j);  // 合并指令
        } else {
            // 查询指令
            int rootI = find(i);
            int rootJ = find(j);
            if (rootI != rootJ) {
                cout << -1 << "\n";  // 不在同一队列
            } else {
                // 计算两战舰间隔的战舰数
                int ans = abs(dist[i] - dist[j]) - 1;
                cout << (ans < 0 ? 0 : ans) << "\n";  // 处理相邻情况
            }
        }
    }
    
    return 0;
}


三、算法核心思想

  1. 带权并查集‌:在普通并查集基础上维护dist数组记录距离

  2. 路径压缩优化‌:find操作同时更新距离信息

  3. 队列合并策略‌:新加入队列的战舰距离等于原队列长度


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。