📌  相关文章
📜  给定 Q 查询的最小频率的彩色树的子树中不同颜色的计数

📅  最后修改于: 2021-10-26 02:27:41             🧑  作者: Mango

给定一个 N-ary 树,它有一些与每个节点和Q查询相关联的颜色。每个查询包含两个整数AX任务是计算以 A为根的子树中所有不同的颜色,在该子树中颜色的频率大于或等于X。
例子:

天真的方法

  • 对于每个查询,我们将遍历给定节点的整个子树。
  • 我们将维护一个映射,该映射存储给定节点的子树中每种颜色的频率。
  • 然后,遍历地图并计算颜色的数量,使其频率大于给定的 x。

时间复杂度: O(Q * N)
空间复杂度: O(Q * N)
方法:(使用Mo的算法)

  • 我们将首先使用 Euler Tour 使树变平。
  • 我们将为每个节点提供编号,以及它何时进入 DFS 以及何时出现。让我们用tin[node]tout[node]来表示每个节点。
  • 在我们将树展平成一个数组后,每个子树都可以表示为某个数组,其开始和结束索引分别为tin[node]tout[node]
  • 现在问题变成了某个子数组中频率大于等于 X的元素的数量。
  • 我们将使用 Mo 算法来解决这个问题。
  • 首先,我们将存储查询并根据tin[node] / SQ对它们进行排序,其中SQN 的平方根。
  • 当我们移动指针时,我们会将第 i 种颜色的频率存储在一个数组中,并将查询的答案存储在数组的第 X个位置,因为它存储了频率大于 X 的颜色计数。
CPP
1(1)
         /       \ 
       /          \
     2(2)         5(3)
    /   \       /  |   \
   /     \     /   |    \
3(2)    4(3) 6(2) 7(3)  8(3)


输出:
// C++ program to count distinct colors
// in a subtree of a Colored Tree
// with given min frequency for Q queries
 
#include 
using namespace std;
 
const int N = 1e5 + 5;
 
// graph as adjacency list
vector > v(N);
 
// colour written on node.
vector colour(N);
 
// order of node entering in DFS
vector in(N);
 
// order of node exiting in DFS
vector out(N);
 
// for counting the frequency of
// nodes with colour i
vector cnt(N);
 
// for storing frequency of colours
vector freq(N);
 
// tree in a flatten
// form (using Euler tour)
vector 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& a,
                pair& 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 > arr,
           int q)
{
    sq = sqrt(n) + 1;
 
    // for storing answers
    vector answer(q);
 
    // for storing indexes of queries
    // in the order of input.
    map, 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 > queries
        = { { 1, 2 },
            { 1, 3 },
            { 1, 4 },
            { 2, 3 },
            { 5, 3 } };
    int q = queries.size();
 
    solve(queries, q);
    return 0;
}

时间复杂度: O(Q * \sqrt{N})
空间复杂度: O(N)