Recuento de colores distintos en un subárbol de un árbol de colores con una frecuencia mínima dada para consultas Q

Dado un árbol N-ario con algún color asociado con cada Node y consultas Q. Cada consulta contiene dos enteros A y X . La tarea es contar todos los colores distintos en un subárbol con raíz en A , que tenga una frecuencia de colores mayor o igual a X en ese subárbol.
Ejemplos: 
 

Entrada: Árbol: 
 

 
           1(1)
         /       \ 
       /          \
     2(2)         5(3)
    /   \       /  |   \
   /     \     /   |    \
3(2)    4(3) 6(2) 7(3)  8(3)

consulta[] = {{1, 2}, {1, 3}, {1, 4}, {2, 3}, {5, 3}} 
Salida: {2, 2, 1, 0, 1} 
Explicación: 
En el subárbol con raíz en 1, la frecuencia del color 2 es 3 y el color 3 es 4. Entonces, la respuesta es 2 para la consulta 1, 2 para la consulta 2 y 1 para la consulta 3. 
Para el subárbol con raíz en 2, la frecuencia del color 2 es 2 y el color 3 es 1. Por lo tanto, ningún color tiene una frecuencia mayor o igual a 4. 
Para el subárbol con raíz en 5, la frecuencia del color 2 es 1 y el color 3 es 3. Entonces, el color 3 tienen frecuencia igual a 3. 
 

Enfoque ingenuo 
 

  • Para cada consulta, recorreremos todo el subárbol del Node dado.
  • Mantendremos un mapa que almacene la frecuencia de cada color en el subárbol de un Node dado.
  • Luego, recorra el mapa y cuente el número de colores tal que su frecuencia sea mayor que la x dada.

Complejidad de tiempo: O(Q * N)  
Complejidad de espacio: O(Q * N)
Enfoque: (usando el algoritmo de Mo) 
 

  • Primero aplanaremos el árbol usando Euler Tour
     
  • Le daremos el número a cada Node, cuándo entrará en el DFS y cuándo saldrá. Denotemos esto con tin[node] y tout[node] para cada Node.
  • Después de aplanar el árbol en una array , cada subárbol de puede denotarse como una array con índice de inicio y final como tin[Node] y tout[Node] respectivamente.
  • Ahora la pregunta cambió a número de elementos con frecuencia mayor que igual a X en algún subarreglo.
  • Usaremos el algoritmo de Mo para resolver este problema.
  • Primero, almacenaremos las consultas y las ordenaremos según tin[node] / SQ donde SQ es la raíz cuadrada de N .
  • A medida que movemos los punteros, almacenaremos la frecuencia en el i-ésimo color en una array y la respuesta a la consulta se almacenará en la X -ésima posición de la array, ya que almacena el recuento de colores con una frecuencia mayor que X.

CPP

// C++ program to count distinct colors
// in a subtree of a Colored Tree
// with given min frequency for Q queries
 
#include <bits/stdc++.h>
using namespace std;
 
const int N = 1e5 + 5;
 
// graph as adjacency list
vector<vector<int> > v(N);
 
// colour written on node.
vector<int> colour(N);
 
// order of node entering in DFS
vector<int> in(N);
 
// order of node exiting in DFS
vector<int> out(N);
 
// for counting the frequency of
// nodes with colour i
vector<int> cnt(N);
 
// for storing frequency of colours
vector<int> freq(N);
 
// tree in a flatten
// form (using Euler tour)
vector<int> flatTree(N);
 
// number of nodes
int n,
 
    // square root of n
    sq;
 
// indexes for in and
// out of node in DFS
int start = 0;
 
// DFS function to find
// order of euler tour
void DFSEuler(int a, int par)
{
 
    // storing the start index
    in[a] = ++start;
 
    // storing colour of node
    // in flatten array
    flatTree[start] = colour[a];
 
    for (int i : v[a]) {
 
        // doing DFS on its child
        // skipping parent
        if (i == par)
            continue;
 
        DFSEuler(i, a);
    }
 
    // out index of the node.
    out[a] = start;
}
 
// comparator for queries
bool comparator(pair<int, int>& a,
                pair<int, int>& b)
{
    // comparator for queries to be
    // sorted according to in[x] / sq
    if (in[a.first] / sq != in[b.first] / sq)
        return in[a.first] < in[b.first];
 
    return out[a.first] < out[b.first];
}
 
// Function to answer the queries
void solve(vector<pair<int, int> > arr,
           int q)
{
    sq = sqrt(n) + 1;
 
    // for storing answers
    vector<int> answer(q);
 
    // for storing indexes of queries
    // in the order of input.
    map<pair<int, int>, int> idx;
 
    for (int i = 0; i < q; i++) {
 
        // storing indexes of queries
        idx[arr[i]] = i;
    }
 
    // doing depth first search to
    // find indexes to flat the
    // tree using euler tour.
    DFSEuler(1, 0);
 
    // After doing Euler tour,
    // subtree of x can be
    // represented as a subarray
    // from in[x] to out[x];
 
    // we'll sort the queries
    // according to the in[i];
    sort(arr.begin(),
         arr.end(),
         comparator);
 
    // two pointers for
    // sliding the window
    int l = 1, r = 0;
 
    for (int i = 0; i < q; i++) {
 
        // finding answer to the query
        int node = arr[i].first,
            x = arr[i].second;
        int id = idx[arr[i]];
 
        while (l > in[node]) {
 
            // decrementing the pointer as
            // it is greater than start
            // and adding answer
            // to our freq array.
            l--;
            cnt[flatTree[l]]++;
            freq[cnt[flatTree[l]]]++;
        }
 
        while (r < out[node]) {
 
            // incrementing pointer as it is
            // less than the end value and
            // adding answer to our freq array.
            r++;
            cnt[flatTree[r]]++;
            freq[cnt[flatTree[r]]]++;
        }
 
        while (l < in[node]) {
 
            // removing the lth node from
            // freq array and incrementing
            // the pointer
            freq[cnt[flatTree[l]]]--;
            cnt[flatTree[l]]--;
            l++;
        }
 
        while (r > out[node]) {
 
            // removing the rth node from
            // freq array and decrementing
            // the pointer
            freq[cnt[flatTree[r]]]--;
            cnt[flatTree[r]]--;
            r--;
        }
 
        // answer to this query
        // is stored at freq[x]
        // freq[x] stores the frequency
        // of nodes greater equal to x
        answer[id] = freq[x];
    }
 
    // printing the queries
    for (int i = 0; i < q; i++)
        cout << answer[i] << " ";
}
 
int main()
{
    // Driver Code
    /*
               1(1)
             /       \
           /          \
         2(2)         5(3)
        /   \       /  |   \
       /     \     /   |    \
    3(2)    4(3) 6(2) 7(3)  8(3)
    */
    n = 8;
    v[1].push_back(2);
    v[2].push_back(1);
    v[2].push_back(3);
    v[3].push_back(2);
    v[2].push_back(4);
    v[4].push_back(2);
    v[1].push_back(5);
    v[5].push_back(1);
    v[5].push_back(6);
    v[6].push_back(5);
    v[5].push_back(7);
    v[7].push_back(5);
    v[5].push_back(8);
    v[8].push_back(5);
 
    colour[1] = 1;
    colour[2] = 2;
    colour[3] = 2;
    colour[4] = 3;
    colour[5] = 3;
    colour[6] = 2;
    colour[7] = 3;
    colour[8] = 3;
 
    vector<pair<int, int> > queries
        = { { 1, 2 },
            { 1, 3 },
            { 1, 4 },
            { 2, 3 },
            { 5, 3 } };
    int q = queries.size();
 
    solve(queries, q);
    return 0;
}
Producción: 

2 2 1 0 1

 

Complejidad de tiempo:  O(Q * \sqrt{N})
Complejidad de espacio: O(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 *