Förutsättningar: BIT DFS
Givet ett rotat träd T med 'n' noder har varje nod en färg betecknad med arrayfärgen[](färg[i] anger färgen på den i:te noden i form av ett heltal). Svara på "Q"-frågor av följande typ:
- distinkt u - Skriv ut antalet distinkta färgade noder under underträdet rotat under 'u'
Exempel:
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'.
Bygg en lösning i steg:
- Platta till trädet med DFS; lagra besökstiden och sluttiden för varje nod i två arrayer vis_tid[i] lagrar besökstiden för ith-noden medan sluttid[i] lagrar sluttiden.
- I samma DFS-anrop lagras färgvärdet för varje nod i en array platt_träd[] vid index: vis_tid[i] och sluttid[i] för sin nod.
Obs: storleken på arrayen plattträd[] blir 2n.
Nu är problemet reducerat till att hitta antalet distinkta element i sortimentet [vis_time[u] end_time[u] ] i arrayen plattträd[] för varje fråga av den angivna typen. För att göra det kommer vi att behandla frågorna offline (bearbetar frågorna i en annan ordning än den som anges i frågan och lagrar resultaten och skriver slutligen ut resultatet för var och en i den ordning som anges i frågan).
Steg:
- Först förbearbetar vi arrayen plattträd[] ; vi upprätthåller en tabell[] (en rad vektorer) tabell[i] lagrar vektorn som innehåller alla index i plattträd[] som har värde i. Det är om plattträd[j] = i sedan tabell[i] kommer att ha ett av dess element j .
- I BIT uppdaterar vi '1' vid ith index om vi vill ha elementet ith av plattträd[] att räknas in fråga() metod. Vi har nu en annan array att korsa[] ; korsa[i] innehåller pekaren till nästa element i tabell[i] som inte är markerat i BIT ännu.
- Vi uppdaterar nu vår BIT och ställer in "1" vid första förekomsten av varje element i platt_träd[] och öka motsvarande att korsa[] av '1'(om platt_träd[i] inträffar för första gången då korsa[platt_träd[i]] ökas med '1') för att peka på nästa förekomst av det elementet.
- Nu vår fråga(R) funktion för BIT skulle returnera antalet distinkta element i plattträd[] i sortimentet [1 R] .
- Vi sorterar alla förfrågningar i ökande ordning show_time[] låta l i beteckna vis_tid[i] och r i beteckna sluttid[i] . Sortera frågorna i ökande ordning l i ger oss ett försprång eftersom vi när vi bearbetar den ith-frågan inte kommer att se någon fråga i framtiden med dess ' l ' mindre än l i . Så vi kan ta bort alla elements förekomster fram till l i - 1 från BIT och lägg till deras nästa förekomster med hjälp av att korsa[] array. Och sedan fråga(R) skulle returnera antalet distinkta element i intervallet [l i r i ] .
// 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);
Produktion:
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) )