给定一个 N-ary 树,它有一些与每个节点和Q查询相关联的颜色。每个查询包含两个整数A和X 。任务是计算以 A为根的子树中所有不同的颜色,在该子树中颜色的频率大于或等于X。
例子:
Input: Tree:
query[] = {{1, 2}, {1, 3}, {1, 4}, {2, 3}, {5, 3}}
Output: {2, 2, 1, 0, 1}
Explanation:
In the subtree rooted at 1, the frequency of colour 2 is 3 and colour 3 is 4. So the answer is 2 for the 1 query, 2 for 2nd query and 1 for 3rd query.
For subtree rooted at 2, frequency of color 2 is 2 and color 3 is 1. So no color have frequency more than or equal to 4.
For subtree rooted at 5, frequency of color 2 is 1 and color 3 is 3. So color 3 have frequency equal to 3.
天真的方法
- 对于每个查询,我们将遍历给定节点的整个子树。
- 我们将维护一个映射,该映射存储给定节点的子树中每种颜色的频率。
- 然后,遍历地图并计算颜色的数量,使其频率大于给定的 x。
时间复杂度: O(Q * N)
空间复杂度: O(Q * N)
方法:(使用Mo的算法)
- 我们将首先使用 Euler Tour 使树变平。
- 我们将为每个节点提供编号,以及它何时进入 DFS 以及何时出现。让我们用tin[node]和tout[node]来表示每个节点。
- 在我们将树展平成一个数组后,每个子树都可以表示为某个数组,其开始和结束索引分别为tin[node]和tout[node] 。
- 现在问题变成了某个子数组中频率大于等于 X的元素的数量。
- 我们将使用 Mo 算法来解决这个问题。
- 首先,我们将存储查询并根据tin[node] / SQ对它们进行排序,其中SQ是N 的平方根。
- 当我们移动指针时,我们会将第 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;
}
时间复杂度:
空间复杂度: