Preduvjeti: BIT DFS
Zadano je ukorijenjeno stablo T s 'n' čvorova, svaki čvor ima boju označenu poljem color[] (boja[i] označava boju i-tog čvora u obliku cijelog broja). Odgovorite na 'Q' upite sljedeće vrste:
- različita u - Ispišite broj različitih obojenih čvorova ispod podstabla ukorijenjenog pod 'u'
Primjeri:
1
/
2 3
/| |
4 5 6 7 8
/|
9 10 11
color[] = {0 2 3 3 4 1 3 4 3 2 1 1}
Indexes NA 1 2 3 4 5 6 7 8 9 10 11
(Node Values and colors start from index 1)
distinct 3 -> output should be '4'.
There are six different nodes in the subtree rooted with
3 nodes are 3 7 8 9 10 and 11. These nodes have
four distinct colors (3 4 2 and 1)
distinct 2 -> output should be '3'.
distinct 7 -> output should be '3'.
Izrada rješenja u koracima:
- Spljoštite stablo pomoću DFS-a; pohranite vrijeme posjete i vrijeme završetka za svaki čvor u dva niza vis_time[i] pohranjuje vrijeme posjete i-tog čvora dok vrijeme završetka[i] pohranjuje vrijeme završetka.
- U istom DFS pozivu pohranite vrijednost boje svakog čvora u nizu ravno_drvo[] kod indeksa: vis_time[i] i vrijeme završetka[i] za i-ti čvor.
Napomena: veličina niza ravno_drvo[] bit će 2n.
Sada se problem svodi na pronalaženje broja različitih elemenata u rasponu [vis_time[u] end_time[u] ] u nizu ravno_drvo[] za svaki upit navedene vrste. Da bismo to učinili, obradit ćemo upite off-line (obrađivanje upita redoslijedom drugačijim od onog navedenog u pitanju i pohranjivanje rezultata te konačno ispisivanje rezultata za svaki redoslijedom navedenim u pitanju).
koraci:
- Prvo prethodno obradimo niz ravno_drvo[] ; održavamo a stol[] (niz vektora) stol[i] pohranjuje vektor koji sadrži sve indekse u ravno_drvo[] koji imaju vrijednost i. To je ako ravno_drvo[j] = i zatim stol[i] imat će jedan od svojih elemenata j .
- U BIT-u ažuriramo '1' na i-tom indeksu ako želimo i-ti element ravno_drvo[] biti uračunat u upit() metoda. Sada održavamo drugi niz prijeći[] ; križ [i] sadrži pokazivač na sljedeći element tablice [i] koji još nije označen u BIT-u.
- Sada ažuriramo naš BIT i postavljamo '1' pri prvom pojavljivanju svakog elementa u ravno_drvo[] i prirast odgovarajući prijeći[] prema '1' (ako ravno_drvo[i] tada se prvi put javlja križ [ravno_drvo[i]] se povećava za '1') kako bi ukazao na sljedeće pojavljivanje tog elementa.
- Sada naš upit(R) funkcija za BIT vratila bi broj različitih elemenata u ravno_drvo[] u rasponu [1 R] .
- Sve upite sortiramo prema rastu vrijeme_prikazivanja[] neka l ja označiti vis_time[i] i r ja označavaju vrijeme završetka[i] . Sortiranje upita u rastućem redoslijedu od l ja daje nam prednost jer prilikom obrade i-tog upita u budućnosti nećemo vidjeti nijedan upit s njegovim ' l ' manji od l ja . Dakle, možemo ukloniti pojavljivanje svih elemenata do l ja - 1 iz BIT-a i dodajte njihova sljedeća pojavljivanja pomoću prijeći[] niz. I tada upit(R) vratio bi broj različitih elemenata u rasponu [l ja r ja ] .
// A C++ program implementing the above design #include #define max_color 1000005 #define maxn 100005 using namespace std; // Note: All elements of global arrays are // initially zero // All the arrays have been described above int bit[maxn] vis_time[maxn] end_time[maxn]; int flat_tree[2 * maxn]; vector<int> tree[maxn]; vector<int> table[max_color]; int traverser[max_color]; bool vis[maxn]; int tim = 0; //li ri and index are stored in queries vector //in that order as the sort function will use //the value li for comparison vector< pair< pair<int int> int> > queries; //ans[i] stores answer to ith query int ans[maxn]; //update function to add val to idx in BIT void update(int idx int val) { while ( idx < maxn ) { bit[idx] += val; idx += idx & -idx; } } //query function to find sum(1 idx) in BIT int query(int idx) { int res = 0; while ( idx > 0 ) { res += bit[idx]; idx -= idx & -idx; } return res; } void dfs(int v int color[]) { //mark the node visited vis[v] = 1; //set visiting time of the node v vis_time[v] = ++tim; //use the color of node v to fill flat_tree[] flat_tree[tim] = color[v]; vector<int>::iterator it; for (it=tree[v].begin(); it!=tree[v].end(); it++) if (!vis[*it]) dfs(*it color); // set ending time for node v end_time[v] = ++tim; // setting its color in flat_tree[] again flat_tree[tim] = color[v]; } //function to add an edge(u v) to the tree void addEdge(int u int v) { tree[u].push_back(v); tree[v].push_back(u); } //function to build the table[] and also add //first occurrences of elements to the BIT void hashMarkFirstOccurrences(int n) { for (int i = 1 ; i <= 2 * n ; i++) { table[flat_tree[i]].push_back(i); //if it is the first occurrence of the element //then add it to the BIT and increment traverser if (table[flat_tree[i]].size() == 1) { //add the occurrence to bit update(i 1); //make traverser point to next occurrence traverser[flat_tree[i]]++; } } } //function to process all the queries and store their answers void processQueries() { int j = 1; for (int i=0; i<queries.size(); i++) { //for each query remove all the occurrences before its li //li is the visiting time of the node //which is stored in first element of first pair for ( ; j < queries[i].first.first ; j++ ) { int elem = flat_tree[j]; //update(i -1) removes an element at ith index //in the BIT update( table[elem][traverser[elem] - 1] -1); //if there is another occurrence of the same element if ( traverser[elem] < table[elem].size() ) { //add the occurrence to the BIT and //increment traverser update(table[elem][ traverser[elem] ] 1); traverser[elem]++; } } //store the answer for the query the index of the query //is the second element of the pair //And ri is stored in second element of the first pair ans[queries[i].second] = query(queries[i].first.second); } } // Count distinct colors in subtrees rooted with qVer[0] // qVer[1] ...qVer[qn-1] void countDistinctColors(int color[] int n int qVer[] int qn) { // build the flat_tree[] vis_time[] and end_time[] dfs(1 color); // add query for u = 3 2 and 7 for (int i=0; i<qn; i++) queries.push_back(make_pair(make_pair(vis_time[qVer[i]] end_time[qVer[i]]) i) ); // sort the queries in order of increasing vis_time sort(queries.begin() queries.end()); // make table[] and set '1' at first occurrences of elements hashMarkFirstOccurrences(n); // process queries processQueries(); // print all the answers in order asked // in the question for (int i=0; i<queries.size() ; i++) { cout << 'Distinct colors in the corresponding subtree' 'is: ' << ans[i] << endl; } } //driver code int main() { /* 1 / 2 3 /| | 4 5 6 7 8 /| 9 10 11 */ int n = 11; int color[] = {0 2 3 3 4 1 3 4 3 2 1 1}; // add all the edges to the tree addEdge(1 2); addEdge(1 3); addEdge(2 4); addEdge(2 5); addEdge(2 6); addEdge(3 7); addEdge(3 8); addEdge(7 9); addEdge(7 10); addEdge(7 11); int qVer[] = {3 2 7}; int qn = sizeof(qVer)/sizeof(qVer[0]); countDistinctColors(color n qVer qn); return 0; }
Java import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main { private static final int maxColor = 1000005; private static final int maxn = 100005; private static int[] bit = new int[maxn]; private static int[] visTime = new int[maxn]; private static int[] endTime = new int[maxn]; private static int[] flatTree = new int[2 * maxn]; private static List<Integer>[] tree = new ArrayList[maxn]; private static List<Integer>[] table = new ArrayList[maxColor]; private static int[] traverser = new int[maxColor]; private static boolean[] vis = new boolean[maxn]; private static int tim = 0; private static List<Pair<Pair<Integer Integer> Integer>> queries = new ArrayList<>(); private static int[] ans = new int[maxn]; private static void update(int idx int val) { while (idx < maxn) { bit[idx] += val; idx += idx & -idx; } } private static int query(int idx) { int res = 0; while (idx > 0) { res += bit[idx]; idx -= idx & -idx; } return res; } private static void dfs(int v int[] color) { vis[v] = true; visTime[v] = ++tim; flatTree[tim] = color[v]; for (int u : tree[v]) { if (!vis[u]) { dfs(u color); } } endTime[v] = ++tim; flatTree[tim] = color[v]; } private static void addEdge(int u int v) { tree[u].add(v); tree[v].add(u); } private static void hashMarkFirstOccurrences(int n) { for (int i = 1; i <= 2 * n; i++) { table[flatTree[i]].add(i); if (table[flatTree[i]].size() == 1) { update(i 1); traverser[flatTree[i]]++; } } } private static void processQueries() { int j = 1; for (Pair<Pair<Integer Integer> Integer> query : queries) { for (; j < query.first.first; j++) { int elem = flatTree[j]; update(table[elem].get(traverser[elem] - 1) -1); if (traverser[elem] < table[elem].size()) { update(table[elem].get(traverser[elem]) 1); traverser[elem]++; } } ans[query.second] = query(query.first.second); } } private static void countDistinctColors(int[] color int n int[] qVer int qn) { dfs(1 color); for (int i = 0; i < qn; i++) { queries.add(new Pair<>(new Pair<>(visTime[qVer[i]] endTime[qVer[i]]) i)); } Collections.sort(queries); hashMarkFirstOccurrences(n); processQueries(); for (int i = 0; i < queries.size(); i++) { System.out.println('Distinct colors in the corresponding subtree is: ' + ans[i]); } } public static void main(String[] args) { int n = 11; int[] color = {0 2 3 3 4 1 3 4 3 2 1 1}; for (int i = 0; i < maxn; i++) { tree[i] = new ArrayList<>(); table[i] = new ArrayList<>(); // Initialize the table array here } addEdge(1 2); addEdge(1 3); addEdge(2 4); addEdge(2 5); addEdge(2 6); addEdge(3 7); addEdge(3 8); addEdge(7 9); addEdge(7 10); addEdge(7 11); int[] qVer = {3 2 7}; int qn = qVer.length; countDistinctColors(color n qVer qn); } static class Pair<A B> implements Comparable<Pair<A B>> { A first; B second; public Pair(A first B second) { this.first = first; this.second = second; } @Override public int compareTo(Pair<A B> other) { if (this.first.equals(other.first)) { return ((Comparable<B>) this.second).compareTo(other.second); } else { return ((Comparable<A>) this.first).compareTo(other.first); } } } }
Python3 # All elements of global arrays are initially zero bit = [0] * 100005 # Binary Indexed Tree (BIT) vis_time = [0] * 100005 # Visiting time for nodes end_time = [0] * 100005 # Ending time for nodes flat_tree = [0] * (2 * 100005) # Flattened tree array tree = [[] for _ in range(100005)] # Tree adjacency list table = [[] for _ in range(1000005)] # Table to store occurrences of colors traverser = [0] * 1000005 # Keeps track of occurrences for each color vis = [False] * 100005 # Visited nodes tim = 0 # Time variable for node traversal queries = [] # Queries to process ans = [0] * 100005 # Stores answers to queries # Update function to add val to idx in BIT def update(idx val): while idx < len(bit): bit[idx] += val idx += idx & -idx # Query function to find sum(1 idx) in BIT def query(idx): res = 0 while idx > 0: res += bit[idx] idx -= idx & -idx return res def dfs(v color): global tim vis[v] = True vis_time[v] = tim = tim + 1 flat_tree[tim] = color[v] # Flattening the tree with node colors for node in tree[v]: # Traverse through adjacent nodes if not vis[node]: dfs(node color) end_time[v] = tim = tim + 1 flat_tree[tim] = color[v] def addEdge(u v): tree[u].append(v) # Add edges to the tree tree[v].append(u) def hashMarkFirstOccurrences(n): # Loop through the flattened tree to mark first occurrences of colors for i in range(1 2 * n + 1): table[flat_tree[i]].append(i) if len(table[flat_tree[i]]) == 1: update(i 1) # Update BIT for first occurrences traverser[flat_tree[i]] += 1 def processQueries(): j = 1 for i in range(len(queries)): # Process queries and update BIT accordingly while j < queries[i][0][0]: elem = flat_tree[j] update(table[elem][traverser[elem] - 1] -1) if traverser[elem] < len(table[elem]): update(table[elem][traverser[elem]] 1) traverser[elem] += 1 j += 1 ans[queries[i][1]] = query(queries[i][0][1]) # Store query answers def countDistinctColors(color n qVer qn): dfs(1 color) # Start depth-first search from node 1 for i in range(qn): queries.append(((vis_time[qVer[i]] end_time[qVer[i]]) i)) # Prepare queries queries.sort() # Sort queries based on visiting time and ending time hashMarkFirstOccurrences(n) # Mark first occurrences in the flattened tree processQueries() # Process queries and update BIT for i in range(len(queries)): print(f'Distinct colors in the corresponding subtree is: {ans[i]}') # Print query answers if __name__ == '__main__': # Sample tree structure and colors n = 11 color = [0 2 3 3 4 1 3 4 3 2 1 1] addEdge(1 2) # Add edges to construct the tree addEdge(1 3) addEdge(2 4) addEdge(2 5) addEdge(2 6) addEdge(3 7) addEdge(3 8) addEdge(7 9) addEdge(7 10) addEdge(7 11) qVer = [3 2 7] # Query nodes qn = len(qVer) countDistinctColors(color n qVer qn) # Count distinct colors in subtrees rooted at query nodes
C# using System; using System.Collections.Generic; using System.Linq; class Program { // Note: All elements of global arrays are // initially zero // All the arrays have been described above const int max_color = 1000005; const int maxn = 100005; static int[] bit = new int[maxn]; static int[] vis_time = new int[maxn]; static int[] end_time = new int[maxn]; static int[] flat_tree = new int[2 * maxn]; static List<int>[] tree = Enumerable.Repeat(0 maxn).Select(x => new List<int>()).ToArray(); static List<int>[] table = Enumerable.Repeat(0 max_color).Select(x => new List<int>()).ToArray(); static int[] traverser = new int[max_color]; static bool[] vis = new bool[maxn]; static int tim = 0; // li ri and index are stored in queries vector // in that order as the sort function will use // the value li for comparison static List<Tuple<Tuple<int int> int>> queries = new List<Tuple<Tuple<int int> int>>(); // ans[i] stores answer to ith query static int[] ans = new int[maxn]; // update function to add val to idx in BIT static void Update(int idx int val) { while (idx < maxn) { bit[idx] += val; idx += idx & -idx; } } // query function to find sum(1 idx) in BIT static int Query(int idx) { int res = 0; while (idx > 0) { res += bit[idx]; idx -= idx & -idx; } return res; } static void Dfs(int v int[] color) { // mark the node visited vis[v] = true; vis_time[v] = ++tim; flat_tree[tim] = color[v]; foreach (int it in tree[v]) if (!vis[it]) Dfs(it color); end_time[v] = ++tim; flat_tree[tim] = color[v]; } //function to add edges to graph static void addEdge(int u int v) { tree[u].Add(v); tree[v].Add(u); } // function to build the table[] and also add // first occurrences of elements to the BIT static void HashMarkFirstOccurrences(int n) { for (int i = 1; i <= 2 * n; i++) { // if it is the first occurrence of the element // then add it to the BIT and increment traverser table[flat_tree[i]].Add(i); if (table[flat_tree[i]].Count == 1) { Update(i 1); traverser[flat_tree[i]]++; } } } // function to process all the queries and store their answers static void ProcessQueries() { int j = 1; // for each query remove all the occurrences before its li // li is the visiting time of the node // which is stored in first element of first pair for (int i = 0; i < queries.Count; i++) { for (; j < queries[i].Item1.Item1; j++) { int elem = flat_tree[j]; Update(table[elem][traverser[elem] - 1] -1); if (traverser[elem] < table[elem].Count) { Update(table[elem][traverser[elem]] 1); traverser[elem]++; } } ans[queries[i].Item2] = Query(queries[i].Item1.Item2); } } // Count distinct colors in subtrees rooted with qVer[0] // qVer[1] ...qVer[qn-1] static void countDistinctColors(int[] color int n int[] qVer int qn) { // build the flat_tree[] vis_time[] and end_time[] Dfs(1 color); // add query for u = 3 2 and 7 for (int i = 0; i < qn; i++) queries.Add(new Tuple<Tuple<int int> int>(new Tuple<int int>(vis_time[qVer[i]] end_time[qVer[i]]) i)); queries.Sort(); HashMarkFirstOccurrences(n); ProcessQueries(); // print all the answers in order asked // in the question for (int i = 0; i < queries.Count; i++) Console.WriteLine('Distinct colors in the corresponding subtree is: {0}' ans[i]); } static void Main(string[] args) { /* 1 / 2 3 /| | 4 5 6 7 8 /| 9 10 11 */ int n = 11; int[] color = { 0 2 3 3 4 1 3 4 3 2 1 1 }; // add all the edges to the tree addEdge(1 2); addEdge(1 3); addEdge(2 4); addEdge(2 5); addEdge(2 6); addEdge(3 7); addEdge(3 8); addEdge(7 9); addEdge(7 10); addEdge(7 11); int[] qVer = { 3 2 7 }; int qn = qVer.Length; countDistinctColors(color n qVer qn); } }
JavaScript // Constants for maximum color maximum nodes and initializing arrays const max_color = 1000005; const maxn = 100005; const bit = new Array(maxn).fill(0); // Binary Indexed Tree const vis_time = new Array(maxn).fill(0); // Visit time for nodes const end_time = new Array(maxn).fill(0); // End time for nodes const flat_tree = new Array(2 * maxn).fill(0); // Flattened tree structure const tree = Array.from({ length: maxn } () => []); // Graph/tree structure const table = Array.from({ length: max_color } () => []); // Table for elements' occurrences const traverser = new Array(max_color).fill(0); // Tracks traversed elements const vis = new Array(maxn).fill(false); // Tracks visited nodes let tim = 0; // Time counter const queries = []; // Array to store queries const ans = new Array(maxn).fill(0); // Array to store answers to queries // Function to update Binary Indexed Tree function Update(idx val) { while (idx < maxn) { bit[idx] += val; idx += idx & -idx; } } // Function to query Binary Indexed Tree function Query(idx) { let res = 0; while (idx > 0) { res += bit[idx]; idx -= idx & -idx; } return res; } // Depth-first search traversal on the tree function Dfs(v color) { vis[v] = true; vis_time[v] = ++tim; flat_tree[tim] = color[v]; tree[v].forEach((it) => { if (!vis[it]) Dfs(it color); }); end_time[v] = ++tim; flat_tree[tim] = color[v]; } // Function to add edges to the tree/graph function addEdge(u v) { tree[u].push(v); tree[v].push(u); } // Function to populate table and BIT with first occurrences function HashMarkFirstOccurrences(n) { for (let i = 1; i <= 2 * n; i++) { table[flat_tree[i]].push(i); if (table[flat_tree[i]].length === 1) { Update(i 1); traverser[flat_tree[i]]++; } } } // Function to process queries and store answers function ProcessQueries() { let j = 1; for (let i = 0; i < queries.length; i++) { for (; j < queries[i][0][0]; j++) { const elem = flat_tree[j]; Update(table[elem][traverser[elem] - 1] -1); if (traverser[elem] < table[elem].length) { Update(table[elem][traverser[elem]] 1); traverser[elem]++; } } ans[queries[i][1]] = Query(queries[i][0][1]); } } // Function to count distinct colors in subtrees function countDistinctColors(color n qVer qn) { Dfs(1 color); // Traverse the tree to generate visit and end times for (let i = 0; i < qn; i++) { // Push queries based on visit and end times to queries array queries.push([[vis_time[qVer[i]] end_time[qVer[i]]] i]); } queries.sort((a b) => a[0][0] - b[0][0]); // Sort queries based on visit times HashMarkFirstOccurrences(n); // Initialize BIT and table with first occurrences ProcessQueries(); // Process queries to calculate distinct colors for (let i = 0; i < queries.length; i++) { console.log(`Distinct colors in the corresponding subtree is: ${ans[i]}`); // Print the answers } } // Define the tree structure and colors const n = 11; const color = [0 2 3 3 4 1 3 4 3 2 1 1]; // Define edges in the tree addEdge(1 2); addEdge(1 3); addEdge(2 4); addEdge(2 5); addEdge(2 6); addEdge(3 7); addEdge(3 8); addEdge(7 9); addEdge(7 10); addEdge(7 11); // Define query vertices and call the function to count distinct colors const qVer = [3 2 7]; const qn = qVer.length; countDistinctColors(color n qVer qn);
Izlaz:
Distinct colors in the corresponding subtree is:4
Distinct colors in the corresponding subtree is:3
Distinct colors in the corresponding subtree is:3
Time Complexity: O( Q * log(n) )