Consultas para encontrar el peso mínimo de un subárbol de Nodes D-distantes como máximo del Node X

Dado un árbol N-ario con raíz en 1 , y una array val[] que consta de pesos asignados a cada Node, y una array Q[][] , que consta de consultas de la forma {X, D} , la tarea para cada consulta es encontrar el mínimo de todos los pesos asignados a los Nodes que están como máximo a una distancia D del Node X.

Ejemplos:

Entrada: Q[][] = {{1, 2}, {2, 1}}, val[] = {1, 2, 3, 3, 5}

           1
          / \
         4   5
        /
       3
      /
     2

Salida:
1
3
Explicación:
Consulta 1: X = 1, D = 2
Los Nodes a una distancia máxima de 2 del Node 1 son {1, 3, 4, 5} y los pesos asignados a estos Nodes son {1, 3, 3, 5} respectivamente.
Por lo tanto, el peso mínimo asignado es 1.
Consulta 2: X = 2, D = 1
Los Nodes a una distancia máxima de 1 del Node 2 son {2, 3} y los pesos asignados a estos Nodes son {2, 3} respectivamente.
Por lo tanto, el peso mínimo asignado es 2.

Entrada: Q[][] = {{1, 2}}, val[] = {1, 2, 4}

            1
           / \
          2   3

Salida: 1

Enfoque ingenuo:
el enfoque más simple para resolver cada consulta es iterar el árbol y encontrar todos los Nodes que estén como máximo a una distancia D del Node X y encontrar el mínimo de todos los pesos asignados a estos Nodes.
Complejidad temporal: O(Q * N)
Espacio auxiliar: O(1)

Enfoque eficiente:
para optimizar el enfoque anterior, siga los pasos a continuación:

  • Implemente el Euler Tour del árbol y asigne un índice a cada Node del árbol.
  • Ahora, en cada índice, almacene la profundidad y el valor asociado con el Node en una array.
  • Cree Merge Sort Tree en la array y ordene el rango de acuerdo con la profundidad de los Nodes.
  • Para cada consulta, se sabe que todos los Nodes del subárbol de X se encuentran entre las arrays in[X] y out[X], donde in y out son el índice en el que los Nodes realizan DFS .
  • En este rango, encuentre el Node ponderado mínimo que tenga una distancia de D como máximo . Cree el árbol de clasificación por combinación y combine los dos rangos de acuerdo con el orden creciente de profundidad y encuentre el prefijo mínimo entre los valores en cada Node del árbol de clasificación por combinación .

A continuación se muestra la implementación del enfoque anterior:

C++

// C++ Program to implement
// the above approach
#include <bits/stdc++.h>
using namespace std;
  
const int INF = 1e9 + 9;
  
/// Function to perform DFs
void dfs(int a, int par, int dep,
         vector<vector<int> >& v,
         vector<int>& depth, vector<int>& in,
         vector<int>& out,
         vector<pair<int, int> >& inv,
         vector<int>& val, int& tim)
{
  
    // Assign depth
    depth[a] = dep;
  
    // Assign in-time
    in[a] = ++tim;
  
    // Store depth and value to
    // construct Merge Sort Tree
    inv[tim] = make_pair(depth[a], val[a]);
    for (int i : v[a]) {
  
        // Skip the parent
        if (i == par)
            continue;
  
        dfs(i, a, dep + 1, v, depth, in,
            out, inv, val, tim);
    }
  
    // Assign out-time
    out[a] = tim;
}
  
// Function to build the Merge Sort Tree
void build(int node, int l, int r,
           vector<vector<pair<int,
                              int> > >& segtree,
           vector<pair<int, int> >& inv)
{
  
    // If the current node is
    // a leaf node
    if (l == r) {
  
        segtree[node].push_back(inv[l]);
        return;
    }
  
    int mid = (l + r) >> 1;
  
    // Recursively build left and right subtree
    build(2 * node + 1, l, mid, segtree, inv);
    build(2 * node + 2, mid + 1, r, segtree, inv);
  
    // Merge left and right node
    // of merge sort tree
    merge(segtree[2 * node + 1].begin(),
          segtree[2 * node + 1].end(),
          segtree[2 * node + 2].begin(),
          segtree[2 * node + 2].end(),
          back_inserter(segtree[node]));
  
    int mn = INF;
  
    for (auto& i : segtree[node]) {
  
        // Compute the prefix minimum
        mn = min(mn, i.second);
        i.second = mn;
    }
}
  
// Function to solve each query
int query(int x, int y, int dep, int node,
          int l, int r,
          vector<vector<pair<int,
                             int> > >& segtree)
{
    // Check for no overlap
    if (l > y || r < x || x > y)
        return INF;
  
    // Condition for complete overlap
    if (x <= l && r <= y) {
  
        // Find the node with
        // depth greater than d;
        auto it
            = upper_bound(segtree[node].begin(),
                          segtree[node].end(),
                          make_pair(dep, INF));
  
        if (it == segtree[node].begin())
  
            // Return if the first depth
            // is greater than d
            return INF;
  
        // Decrement the pointer;
        it--;
  
        // Return prefix minimum
        return it->second;
    }
    int mid = (l + r) >> 1;
    int a = query(x, y, dep, 2 * node + 1,
                  l, mid, segtree);
  
    int b = query(x, y, dep, 2 * node + 2,
                  mid + 1, r, segtree);
  
    return min(a, b);
}
  
// Function to compute the queries
void answerQueries(vector<pair<int, int> > queries,
                   vector<vector<int> >& v,
                   vector<int> val, int n)
{
    // Stores the time
    int tim = 0;
  
    // Stores the in and out time
    vector<int> in(n + 10), out(n + 10);
  
    // Stores depth
    vector<int> depth(n + 10);
  
    vector<pair<int, int> > inv(n + 10);
    dfs(1, 0, 0, v, depth, in, out, inv, val, tim);
  
    // Merge sort tree to store
    // depth of each node
    vector<vector<pair<int,
                       int> > >
        segtree(4 * n + 10);
  
    // Construct the merge sort tree
    build(0, 1, tim, segtree, inv);
  
    for (auto& i : queries) {
  
        int x = i.first;
        int dep = depth[x] + i.second;
  
        // Find the minimum value in subtree of x
        // and subtree of x lies from in[x]
        // to out[x] in merge sort tree
        int minVal = query(in[x], out[x], dep, 0,
                           1, tim, segtree);
        cout << minVal << endl;
    }
}
  
// Driver Code
int main()
{
  
    /*
                    1
                   /  \
                 4     5
                /
               3
              /
            2
    */
    int n = 5;
  
    // Stores the graph
    vector<vector<int> > v(n + 1);
  
    // Stores the weights
    vector<int> val(n + 1);
  
    // Assign edges
    v[1].push_back(4);
    v[4].push_back(1);
    v[1].push_back(5);
    v[5].push_back(1);
    v[4].push_back(3);
    v[3].push_back(4);
    v[3].push_back(2);
    v[2].push_back(3);
  
    // Assign weights
    val[1] = 1;
    val[2] = 3;
    val[3] = 2;
    val[4] = 3;
    val[5] = 5;
  
    // Stores the queries
    vector<pair<int, int> > queries = { { 1, 2 },
                                        { 2, 1 } };
  
    answerQueries(queries, v, val, n);
    return 0;
}
Producción:

1
3

Complejidad de tiempo: O(N * log(N) + Q * log(N))
Espacio auxiliar: O(N * log N)

Publicación traducida automáticamente

Artículo escrito por insiderpants y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *