Задача А: Реструктуризация компании В жизни даже ...
Créé le : 15 mars 2025
Créé le : 15 mars 2025
Задача А: Реструктуризация компании
В жизни даже самой успешной компании может наступить кризисный период, когда приходится принимать тяжёлое решение о реструктуризации, распускать и объединять отделы, увольнять работников и заниматься прочими неприятными делами. Рассмотрим следующую модель компании.
В Большой Софтверной Компании работают и человек. Каждый человек принадлежит какому-то отделу. Исходно каждый человек работает над своим проектом в своём собственном отделе (таким образом, в начале компания состоит из и отделов по одному человеку).
Однако, в жизни компании наступили тяжёлые времена, и руководство было вынуждено нанять кризисного менеджера, который начал переустраивать рабочий процесс для повышения эффективности производства. Обозначим за team(person) команду, в которой работает человек person. Кризисный менеджер может принимать решения одного типа:
Ниже приведён пример максимально быстрой реализации на C++ с использованием структуры «Система непересекающихся множеств» (DSU/Union-Find). Код читает входные данные, обрабатывает запросы объединения (type=1) и для каждого запроса проверки (type=3) отвечает «YES» или «NO».
Основные моменты для скорости:
cin.tie(nullptr) для ускоренного чтения.cpp#include <bits/stdc++.h> using namespace std; struct DSU { vector<int> parent, size_; DSU(int n) { parent.resize(n+1); size_.resize(n+1, 1); for(int i = 1; i <= n; i++){ parent[i] = i; } } // Функция "найти" с сжатием пути (path compression) int find_set(int v) { if(v == parent[v]) return v; return parent[v] = find_set(parent[v]); } // Объединение по размеру (union by size) void union_set(int a, int b) { a = find_set(a); b = find_set(b); if(a != b) { if(size_[a] < size_[b]) swap(a,b); parent[b] = a; size_[a] += size_[b]; } } }; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int n, q; cin >> n >> q; DSU dsu(n); while(q--) { int type, x, y; cin >> type >> x >> y; if(type == 1) { // Объединение отделов dsu.union_set(x, y); } else if(type == 3) { // Проверка, в одном ли отделе if(dsu.find_set(x) == dsu.find_set(y)) cout << "YES\n"; else cout << "NO\n"; } } return 0; }
Пояснения:
DSU/Union-Find:
find_set(v) находит «корень» для элемента v. Если v не является корнем, мы рекурсивно поднимаемся по цепочке родителей и одновременно «сжимаем путь», чтобы в дальнейшем поиск проходил быстрее.union_set(a, b) объединяет множества, в которых находятся a и b. Для оптимизации объединения мы выбираем корень множества с большим размером (или рангом) в качестве нового корня, чтобы глубина дерева не росла слишком быстро.Сложность:
O(α(n)), где α — очень медленно растущая функция (обратная функция Аккермана). Для всех практических целей это практически константа.n до 200000 и q до 500000 решение будет работать достаточно быстро при корректной реализации.Таким образом, программа обрабатывает все запросы объединения и проверки принадлежности к одному отделу за приемлемое время.