Open In App

Maximizing Odd sum in Weighted Tree with Special Operation

Last Updated : 31 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a tree with N nodes numbered from 0 to N-1. The tree is rooted at 0. The tree is denoted by an array where the element at i’th index denotes the parent of i’th node. There is an array of size N denoting the weights of the nodes. Find the maximum possible odd sum that can be obtained from any subtree by performing at most 1 special operation. The special operation is to change the weight of one of the nodes to 0. If it is not possible to obtain an odd sum return -1.

Examples:

Input: Parent array = {-1, 0, 0, 1, 1, 2}, Weights = {5, 3, 1, 1, 3, 3}
Output: 15
Explanation: We can make the weight of node 2 as 0, to obtain the maximum odd sum of 15.

Input: Parent Array = {-1, 0, 0, 1, 1, 2}, Weights = {-5, 3, -1, 1, 3, 3}
Output: 9
Explanation: We can have a subtree rooted at 0 to get the maximum odd sum of 9 by making node 0 with weight 0.

Approach: This can be solved with the following idea:

The main idea is to use depth-first traversal of the tree, keeping track of the sum, minimum odd weight, and minimum even weight of each subtree. This allows for calculating the maximum possible odd sum with or without using the special operation.

Below are the steps involved:

  • Initialize an adjacency list (adj) to represent the tree structure and set the variable ans to a large negative value to keep track of the maximum possible odd sum.
  • Perform a depth-first traversal (DFS) of the tree starting from the root node (node 0). The DFS function takes the parent node, current node, and the weights of the nodes as parameters:
    • In each recursive call of the DFS function, update the sum (su) by adding the weight of the current node and calculate the minimum odd and even weights (miOdd and miEven) within the subtree.
    • For each child of the current node, recursively call the DFS function and update the sum, minimum odd, and minimum even weights by considering the contributions from all child subtrees.
    • Update miOdd and miEven if the weight of the current node is smaller than the previously calculated minimums.
    • Determine whether the current sum is even or odd. If it’s even, consider whether subtracting the minimum odd weight (miOdd) can result in a larger odd sum. If it’s odd, consider whether subtracting the minimum even weight (miEven) can result in a larger odd sum.
    • Update ans with the maximum of the current ans and the calculated sum considering the special operation.
  • After DFS traversal is complete, check if ans is still set to the initial large negative value. If it is, it means it’s not possible to obtain an odd sum, so set ans to -1.
  • Return the value of ans as the maximum possible odd sum with or without using the special operation.

Below is the implementation of the code:

C++




// C++ code for the above approach:
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
 
// Declaration of adj vector
vector<vector<int> > adj;
int ans;
 
vector<int> dfs(int par, int node, vector<int>& wei)
{
    int su = 0;
    int miOdd = 1e9;
    int miEven = 1e9;
 
    // Iterate from parent node
    for (int i : adj[node]) {
        if (i != par) {
 
            // Iterate for next node found
            vector<int> li = dfs(node, i, wei);
 
            // Add the sum
            su += li[0];
 
            // Update the min odd and
            // even values
            miOdd = min(miOdd, li[1]);
            miEven = min(miEven, li[2]);
        }
    }
 
    // Add the sum
    su += wei[node];
 
    // If current node is even
    if (wei[node] % 2 == 0) {
        miEven = min(miEven, wei[node]);
    }
    else {
        miOdd = min(miOdd, wei[node]);
    }
 
    // If sum is even
    if (su % 2 == 0) {
        if (miOdd != 1e9) {
            ans = max(ans, su - miOdd);
        }
    }
 
    // Check by subtracting minimum even
    // value in the path
    else {
        if (miEven < 0) {
            ans = max(ans, su - miEven);
        }
        else {
            ans = max(ans, su);
        }
    }
 
    return { su, miOdd, miEven };
}
 
// Function to have maximum
// possible odd sum
int maximumOddSum(vector<int>& par, vector<int>& wei)
{
    ans = 0;
    int n = par.size();
    adj.clear();
    adj.resize(n + 10);
    ans = -1e9;
 
    // Create a adj vector from given array
    for (int i = 1; i < n; i++) {
 
        int u = i;
        int v = par[i];
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
 
    // Function call to iterate
    dfs(-1, 0, wei);
 
    // If sum found is not odd
    if (ans == -1e9) {
        ans = -1;
    }
 
    // Retur maximum possible sum
    return ans;
}
 
// Driver code
int main()
{
 
    vector<int> par = { -1, 0, 0, 1, 1, 2 };
    vector<int> wei = { 5, 3, 1, 1, 3, 3 };
 
    // Function call
    cout << maximumOddSum(par, wei);
    return 0;
}


Java




// Java code for the above approach:
import java.util.*;
 
class GFG {
    static List<List<Integer> > adj;
    static int ans;
 
    static List<Integer> dfs(int par, int node,
                             List<Integer> wei)
    {
        int su = 0;
        int miOdd = Integer.MAX_VALUE;
        int miEven = Integer.MAX_VALUE;
 
        // Iterate through adjacent nodes
        for (int i : adj.get(node)) {
            if (i != par) {
                List<Integer> li = dfs(node, i, wei);
 
                // Add the sum
                su += li.get(0);
 
                // Update the min odd and even values
                miOdd = Math.min(miOdd, li.get(1));
                miEven = Math.min(miEven, li.get(2));
            }
        }
 
        // Add the sum
        su += wei.get(node);
 
        // Check if current node's weight is even or odd
        if (wei.get(node) % 2 == 0) {
            miEven = Math.min(miEven, wei.get(node));
        }
        else {
            miOdd = Math.min(miOdd, wei.get(node));
        }
 
        // Check for even and odd sums and update answer
        if (su % 2 == 0) {
            if (miOdd != Integer.MAX_VALUE) {
                ans = Math.max(ans, su - miOdd);
            }
        }
        else {
            if (miEven < 0) {
                ans = Math.max(ans, su - miEven);
            }
            else {
                ans = Math.max(ans, su);
            }
        }
 
        // Return the calculated values
        List<Integer> result = new ArrayList<>();
        result.add(su);
        result.add(miOdd);
        result.add(miEven);
        return result;
    }
 
    static int maximumOddSum(List<Integer> par,
                             List<Integer> wei)
    {
        ans = 0;
        int n = par.size();
        adj = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            adj.add(new ArrayList<>());
        }
        ans = Integer.MIN_VALUE;
 
        // Create an adjacency list from the given array
        for (int i = 1; i < n; i++) {
            int u = i;
            int v = par.get(i);
            adj.get(u).add(v);
            adj.get(v).add(u);
        }
 
        // Function call for DFS
        dfs(-1, 0, wei);
 
        // If the sum found is not odd
        if (ans == Integer.MIN_VALUE) {
            ans = -1;
        }
 
        // Return the maximum possible sum
        return ans;
    }
 
    public static void main(String[] args)
    {
        List<Integer> par = List.of(-1, 0, 0, 1, 1, 2);
        List<Integer> wei = List.of(5, 3, 1, 1, 3, 3);
 
        // Function call
        System.out.println(maximumOddSum(par, wei));
    }
}


Python3




from typing import List, Tuple
 
# Declaration of adj list
adj = []
ans = 0
 
def dfs(par: int, node: int, wei: List[int]) -> Tuple[int, int, int]:
    global ans
    su = 0
    miOdd = float('inf')
    miEven = float('inf')
 
    # Iterate from parent node
    for i in adj[node]:
        if i != par:
 
            # Iterate for next node found
            li = dfs(node, i, wei)
 
            # Add the sum
            su += li[0]
 
            # Update the min odd and even values
            miOdd = min(miOdd, li[1])
            miEven = min(miEven, li[2])
 
    # Add the sum
    su += wei[node]
 
    # If current node is even
    if wei[node] % 2 == 0:
        miEven = min(miEven, wei[node])
    else:
        miOdd = min(miOdd, wei[node])
 
    # If sum is even
    if su % 2 == 0:
        if miOdd != float('inf'):
            ans = max(ans, su - miOdd)
 
    # Check by subtracting minimum even value in the path
    else:
        if miEven < 0:
            ans = max(ans, su - miEven)
        else:
            ans = max(ans, su)
 
    return su, miOdd, miEven
 
# Function to have maximum possible odd sum
def maximumOddSum(par: List[int], wei: List[int]) -> int:
    global ans
    ans = 0
    n = len(par)
    global adj
    adj = [[] for _ in range(n + 10)]
    ans = float('-inf')
 
    # Create an adj list from the given array
    for i in range(1, n):
        u = i
        v = par[i]
        adj[u].append(v)
        adj[v].append(u)
 
    # Function call to iterate
    dfs(-1, 0, wei)
 
    # If sum found is not odd
    if ans == float('-inf'):
        ans = -1
 
    # Return maximum possible sum
    return ans
 
# Driver code
if __name__ == "__main__":
    par = [-1, 0, 0, 1, 1, 2]
    wei = [5, 3, 1, 1, 3, 3]
 
    # Function call
    print(maximumOddSum(par, wei))
 
# This code is contributed by rambabuguphka


C#




using System;
using System.Collections.Generic;
 
class Program
{
    // Declaration of adj List
    static List<List<int>> adj;
    static int ans;
 
    static List<int> DFS(int par, int node, List<int> wei)
    {
        int su = 0;
        int miOdd = int.MaxValue;
        int miEven = int.MaxValue;
 
        // Iterate from parent node
        foreach (int i in adj[node])
        {
            if (i != par)
            {
                // Iterate for next node found
                List<int> li = DFS(node, i, wei);
 
                // Add the sum
                su += li[0];
 
                // Update the min odd and even values
                miOdd = Math.Min(miOdd, li[1]);
                miEven = Math.Min(miEven, li[2]);
            }
        }
 
        // Add the sum
        su += wei[node];
 
        // If current node is even
        if (wei[node] % 2 == 0)
        {
            miEven = Math.Min(miEven, wei[node]);
        }
        else
        {
            miOdd = Math.Min(miOdd, wei[node]);
        }
 
        // If sum is even
        if (su % 2 == 0)
        {
            if (miOdd != int.MaxValue)
            {
                ans = Math.Max(ans, su - miOdd);
            }
        }
 
        // Check by subtracting minimum even value in the path
        else
        {
            if (miEven < 0)
            {
                ans = Math.Max(ans, su - miEven);
            }
            else
            {
                ans = Math.Max(ans, su);
            }
        }
 
        return new List<int> { su, miOdd, miEven };
    }
 
    // Function to have maximum possible odd sum
    static int MaximumOddSum(List<int> par, List<int> wei)
    {
        ans = 0;
        int n = par.Count;
        adj = new List<List<int>>();
        for (int i = 0; i < n + 10; i++)
        {
            adj.Add(new List<int>());
        }
        ans = int.MinValue;
 
        // Create an adj List from given array
        for (int i = 1; i < n; i++)
        {
            int u = i;
            int v = par[i];
            adj[u].Add(v);
            adj[v].Add(u);
        }
 
        // Function call to iterate
        DFS(-1, 0, wei);
 
        // If sum found is not odd
        if (ans == int.MinValue)
        {
            ans = -1;
        }
 
        // Return maximum possible sum
        return ans;
    }
 
    // Driver code
    public static void Main(string[] args)
    {
        List<int> par = new List<int> { -1, 0, 0, 1, 1, 2 };
        List<int> wei = new List<int> { 5, 3, 1, 1, 3, 3 };
 
        // Function call
        Console.WriteLine(MaximumOddSum(par, wei));
    }
}


Javascript




// javaScript code for the above approach
 
let adj; // Adjacency List
let ans; // Stores the maximum odd sum
 
// DFS traversal to calculate sums
// and min values
function dfs(par, node, wei) {
    let su = 0;
    let miOdd = 1e9;
    let miEven = 1e9;
 
    // Traverse through adjacent nodes
    for (let i of adj[node]) {
        if (i !== par) {
            let li = dfs(node, i, wei);
            su += li[0];
            miOdd = Math.min(miOdd, li[1]);
            miEven = Math.min(miEven, li[2]);
        }
    }
 
    su += wei[node];
 
    // Update min odd/even values
    // based on current node value
    if (wei[node] % 2 === 0) {
        miEven = Math.min(miEven, wei[node]);
    }
    else {
        miOdd = Math.min(miOdd, wei[node]);
    }
 
    // Calculate the maximum odd sum
    if (su % 2 === 0) {
        if (miOdd !== 1e9) {
            ans = Math.max(ans, su - miOdd);
        }
    }
    else {
        if (miEven < 0) {
            ans = Math.max(ans, su - miEven);
        }
        else {
            ans = Math.max(ans, su);
        }
    }
 
    return [su, miOdd, miEven];
}
 
// Function to find the maximum possible odd sum
function maximumOddSum(par, wei) {
    ans = 0;
    const n = par.length;
 
    // Initialize adjacency list
    adj = Array.from({ length: n + 10 }, () => []);
 
    ans = -1e9;
 
    // Construct adjacency list
    for (let i = 1; i < n; i++) {
        const u = i;
        const v = par[i];
        adj[u].push(v);
        adj[v].push(u);
    }
 
    // Start DFS traversal from root node
    dfs(-1, 0, wei);
 
    // If no odd sum found, assign -1
    if (ans === -1e9) {
        ans = -1;
    }
 
    return ans;
}
 
// Driver function
 
const par = [-1, 0, 0, 1, 1, 2];
const wei = [5, 3, 1, 1, 3, 3];
 
// Call the function
console.log(maximumOddSum(par, wei));


Output

15










Time Complexity: O(N)
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads