Минимальный путь при запросе взвешенного дерева

Дано взвешенное дерево с n вершинами. имеется q запросов, и для каждого запроса заданы целые числа (u,k). Найдите количество вершин v таких, что наименьшее ребро на пути из u в v равно k. (п, д <= 1e5)

я пробовал использовать dfs, но лучшее решение, которое я мог придумать, это O(n*q)

Мой текущий код:

#include <bits/stdc++.h>
 
using namespace std;

const int INF = 1e9;

struct Edge {
    int to;
    int weight;
};
 
vector<vector<Edge>> adj;
vector<int> mn;

void dfs(int u, int parent, int minWeight) {
    mn[u] = minWeight;
    for (auto edge : adj[u]) {
        if (edge.to != parent) {
            dfs(edge.to, u, min(minWeight, edge.weight));
        }
    }
}
 
int main() {
    int n, q;
    cin >> n >> q;
    adj.resize(n + 1);
    mn.resize(n + 1);
    for (int i = 0; i < n - 1; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
    }
    while (q--) {
        int u, k;
        cin >> u >> k;
        fill(mn.begin(), mn.end(), INF);
        dfs(u, -1, INF);
        int cnt = 0;
        for (int v = 1; v <= n; ++v) {
            if (v != u && mn[v] == k) {
                cnt++;
            }
        }
 
        cout << cnt << endl;
    }
 
    return 0;
}

я только что добавил свой код

turtle silver 08.07.2024 17:36

Было бы лучше, если бы вы могли указать требуемое время выполнения/сложность времени. Кроме того, если эта проблема связана с веб-сайтом, вам следует дать ссылку на него.

Tom Lin 09.07.2024 06:05

Подсказка: предположим, что имеется d различных весов ребер. Начните с удаления всех ребер, а затем добавьте их обратно в порядке убывания веса за d этапов, так чтобы на каждом этапе мы добавляли все ребра одинакового веса. Пусть compSize(x, i) — количество вершин в связном компоненте, содержащем вершину x, после i этапов, и пусть j — этап, на котором добавляются все ребра веса k. Тогда ответом на вопрос для (u, k) будет compSize(что-то) - compSize(что-то подобное). (Даже если вы зайдете так далеко, вам все равно понадобится способ эффективно вычислять и сохранять compSize()...)

j_random_hacker 09.07.2024 07:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
3
108
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Эту проблему можно решить в автономном режиме, сначала прочитав все запросы, а затем отсортировав их по весу ребра в невозрастающем порядке. Мы можем использовать непересекающийся набор, чтобы поддерживать лес, сформированный только с использованием ребер с весом, превышающим определенное значение. Мы также сортируем ребра в дереве в порядке невозрастания и добавляем ребра определенного веса обратно в этом порядке. Всякий раз, когда мы добавляем ребра обратно, мы проверяем наличие запросов для этого конкретного веса. Увеличение размера компонента для любого узла после добавления этих ребер обратно — это количество вершин, у которых этот вес ребра является минимальным на пути. Обратите внимание, что запросы на веса ребер, которых нет в дереве, всегда приводят к 0.

Мы можем использовать модифицированную версию непересекающегося набора, в которой корень каждого компонента хранит отрицательный размер компонента, чтобы упростить ответ на запросы, а также реализовать объединение по размеру. Временная сложность этого решения равна O(N log N + (N + Q) log Q + (N + Q)α(N)) (где α — обратная функция Аккермана, которая здесь фактически постоянна).

Эту проблему можно решить онлайн, но код становится намного сложнее.

#include <vector>
#include <iostream>
#include <map>
#include <functional>
#include <utility>
std::vector<int> ds; // the disjoint set
int find(int u) {
    return ds[u] < 0 ? u : ds[u] = find(ds[u]);
}
int main() {
    int n, q;
    std::cin >> n >> q;
    std::vector<int> answers(q);
    ds.assign(n + 1, -1);
    std::map<int, std::vector<std::pair<int, int>>, std::greater<>> edgesForWeight, queriesForWeight;
    for (int i = 1, u, v, w; i < n; ++i) {
        std::cin >> u >> v >> w;
        edgesForWeight[w].push_back({u, v});
    }
    for (int i = 0, u, k; i < q; ++i) {
        std::cin >> u >> k;
        queriesForWeight[k].push_back({i, u});
    }
    for (const auto& [weight, edges] : edgesForWeight) {
        auto queriesIt = queriesForWeight.find(weight);
        if (queriesIt != queriesForWeight.end())
            for (auto [qidx, node] : queriesIt->second)
                answers[qidx] = ds[find(node)];
        for (auto [u, v] : edges) {
            u = find(u), v = find(v);
            if (ds[u] > ds[v]) std::swap(u, v);
            ds[u] += ds[v];
            ds[v] = u;
        }
        if (queriesIt != queriesForWeight.end())
            for (auto [qidx, node] : queriesIt->second)
                answers[qidx] -= ds[find(node)];
    }
    for (int ans : answers) std::cout << ans << '\n';
}

Другие вопросы по теме