Skip to content
geeksforgeeks
  • Tutorials
    • Python
    • Java
    • Data Structures & Algorithms
    • ML & Data Science
    • Interview Corner
    • Programming Languages
    • Web Development
    • CS Subjects
    • DevOps And Linux
    • School Learning
    • Practice Coding Problems
  • Courses
    • DSA to Development
    • Get IBM Certification
    • Newly Launched!
      • Master Django Framework
      • Become AWS Certified
    • For Working Professionals
      • Interview 101: DSA & System Design
      • Data Science Training Program
      • JAVA Backend Development (Live)
      • DevOps Engineering (LIVE)
      • Data Structures & Algorithms in Python
    • For Students
      • Placement Preparation Course
      • Data Science (Live)
      • Data Structure & Algorithm-Self Paced (C++/JAVA)
      • Master Competitive Programming (Live)
      • Full Stack Development with React & Node JS (Live)
    • Full Stack Development
    • Data Science Program
    • All Courses
  • DSA
  • Interview Problems on Graph
  • Practice Graph
  • MCQs on Graph
  • Graph Tutorial
  • Graph Representation
  • Graph Properties
  • Types of Graphs
  • Graph Applications
  • BFS on Graph
  • DFS on Graph
  • Graph VS Tree
  • Transpose Graph
  • Dijkstra's Algorithm
  • Minimum Spanning Tree
  • Prim’s Algorithm
  • Topological Sorting
  • Floyd Warshall Algorithm
  • Strongly Connected Components
  • Advantages & Disadvantages
Open In App
Next Article:
CSES Solutions - Fixed-Length Paths II
Next article icon

CSES Solutions - Fixed-Length Paths II

Last Updated : 28 Apr, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Given a tree of n nodes, the task is to count the number of distinct paths that have at least k1 and at most k2 edges.

Example:

Input: n = 5, k1 = 2, k2 = 3, edges = {{1, 2}, {2 ,3}, {3, 4}, {3, 5}}
Output: 6

Input: n = 5, k1 = 1, k2 = 4, edges = { { 1, 2 }, { 2, 3 }, { 3, 4 }, { 3, 5 } }
Output: 10

Approach:

This solution is a simple extension of CSES Fixed-Length Paths I's solution.

The main idea is to use centroid decomposition to divide the tree into smaller subtrees. Within each subtree, the get_cnt function counts paths based on the depth of nodes. The Fenwick tree is used to efficiently query and update the number of paths within specific depth ranges. The final answer is obtained by summing the counts from all subtrees.

Let's break down the Ideas:

Centroid Decomposition:

  • Find the centroid of the tree, which is the node that minimizes the maximum distance to any other node.
  • Recursively decompose the tree into subtrees rooted at the centroids.

Fenwick Tree:

  • Use a Fenwick tree (Binary Indexed Tree) to efficiently store and update counts of paths within the desired length range.

Counting Paths:

  • For each subtree rooted at a centroid, count paths that pass through the centroid and satisfy the length range.
  • Use the Fenwick tree to query the number of paths within the range for each depth level.

Steps-by-step approach:

  • Perform centroid decomposition to break the tree into subtrees.
  • Initialize the Fenwick tree with the root node.
  • For each subtree, recursively count paths and update the Fenwick tree.
  • Query the Fenwick tree to obtain the final count of paths within the specified length range.

Below is the implementation of the above approach:

C++
#include <bits/stdc++.h> typedef long long ll; using namespace std;  int n, a, b;  // Adjacency list representation of the tree vector<int> graph[200001];  // Size of subtree rooted at each node int subtree[200001];  // ans stores the final answer, bit is for Fenwick tree // (Binary Indexed Tree) ll ans = 0, bit[200001];  // Maximum depth encountered during centroid decomposition int mx_depth;  // To mark nodes as processed during centroid decomposition bool processed[200001];  // Function to calculate subtree sizes rooted at each node int get_subtree_sizes(int node, int parent = 0) {     subtree[node] = 1;     for (int i : graph[node])         if (!processed[i] && i != parent)             subtree[node] += get_subtree_sizes(i, node);     return subtree[node]; }  // Function to find the centroid of a subtree int get_centroid(int desired, int node, int parent = 0) {     for (int i : graph[node])         if (!processed[i] && i != parent             && subtree[i] >= desired)             return get_centroid(desired, i, node);     return node; }  // Function to update Fenwick tree void update(int pos, ll val) {     for (pos++; pos <= n; pos += pos & -pos)         bit[pos] += val; }  // Function to query Fenwick tree for sum in a range ll query(int l, int r) {     ll ans = 0;     for (r++; r; r -= r & -r)         ans += bit[r];     for (; l; l -= l & -l)         ans -= bit[l];     return ans; }  // Function to count paths in a subtree within a certain // depth range void get_cnt(int node, int parent, bool filling,              int depth = 1) {      // Depth exceeds limit, stop recursion     if (depth > b)         return;      // Update maximum depth encountered     mx_depth = max(mx_depth, depth);      // Fill the Fenwick tree if filling is true     if (filling)         update(depth, 1);      // Otherwise, query the Fenwick tree for counts     else         ans += query(max(0, a - depth), b - depth);     for (int i : graph[node])         if (!processed[i] && i != parent)             get_cnt(i, node, filling, depth + 1); }  // Centroid decomposition of the tree void centroid_decomp(int node = 1) {      // Find centroid of the subtree     int centroid         = get_centroid(get_subtree_sizes(node) >> 1, node);      // Mark centroid as processed     processed[centroid] = true;      // Initialize maximum depth encountered to 0     mx_depth = 0;      // Iterate through centroid's neighbors     for (int i : graph[centroid])         if (!processed[i]) {              // Count paths passing through each neighbor             get_cnt(i, centroid, false);              // Update Fenwick tree for each neighbor             get_cnt(i, centroid, true);         }      // Clear Fenwick tree values after processing     for (int i = 1; i <= mx_depth; i++)         update(i, -query(i, i));      // Recursively decompose remaining subtrees     for (int i : graph[centroid])         if (!processed[i])             centroid_decomp(i); }  int main() {     // Static input     n = 5;      a = 1; // or K1     b = 4; // or K2     vector<vector<int> > edges         = { { 1, 2 }, { 2, 3 }, { 3, 4 }, { 3, 5 } };      for (int i = 0; i < edges.size(); i++) {         int u = edges[i][0];         int v = edges[i][1];          graph[u].push_back(v);         graph[v].push_back(u);     }      // Initialize Fenwick tree with root node     update(0, 1);      // Perform centroid decomposition     centroid_decomp();      // Output the final answer     cout << ans;     return 0; } 
Java
import java.util.*;  public class Main {     static int n, a, b;     static ArrayList<Integer>[] graph; // Adjacency list representation of the tree     static int[] subtree; // Size of subtree rooted at each node     static long ans = 0; // ans stores the final answer     static long[] bit; // bit is for Fenwick tree (Binary Indexed Tree)     static int mx_depth; // Maximum depth encountered during centroid decomposition     static boolean[] processed; // To mark nodes as processed during centroid decomposition      // Function to calculate subtree sizes rooted at each node     static int getSubtreeSizes(int node, int parent) {         subtree[node] = 1;         for (int i : graph[node]) {             if (!processed[i] && i != parent) {                 subtree[node] += getSubtreeSizes(i, node);             }         }         return subtree[node];     }      // Function to find the centroid of a subtree     static int getCentroid(int desired, int node, int parent) {         for (int i : graph[node]) {             if (!processed[i] && i != parent && subtree[i] >= desired) {                 return getCentroid(desired, i, node);             }         }         return node;     }      // Function to update Fenwick tree     static void update(int pos, long val) {         for (pos++; pos <= n; pos += pos & -pos) {             bit[pos] += val;         }     }      // Function to query Fenwick tree for sum in a range     static long query(int l, int r) {         long ans = 0;         for (r++; r > 0; r -= r & -r) {             ans += bit[r];         }         for (; l > 0; l -= l & -l) {             ans -= bit[l];         }         return ans;     }      // Function to count paths in a subtree within a certain depth range     static void getCnt(int node, int parent, boolean filling, int depth) {         if (depth > b) return;         mx_depth = Math.max(mx_depth, depth);         if (filling) update(depth, 1);         else ans += query(Math.max(0, a - depth), b - depth);         for (int i : graph[node]) {             if (!processed[i] && i != parent) {                 getCnt(i, node, filling, depth + 1);             }         }     }      // Centroid decomposition of the tree     static void centroidDecomp(int node) {         int centroid = getCentroid(getSubtreeSizes(node, 0) >> 1, node, 0);         processed[centroid] = true;         mx_depth = 0;         for (int i : graph[centroid]) {             if (!processed[i]) {                 getCnt(i, centroid, false, 1);                 getCnt(i, centroid, true, 1);             }         }         for (int i = 1; i <= mx_depth; i++) {             update(i, -query(i, i));         }         for (int i : graph[centroid]) {             if (!processed[i]) {                 centroidDecomp(i);             }         }     }      public static void main(String[] args) {         n = 5;         a = 1;         b = 4;         ArrayList<ArrayList<Integer>> edges = new ArrayList<>();         edges.add(new ArrayList<>(Arrays.asList(1, 2)));         edges.add(new ArrayList<>(Arrays.asList(2, 3)));         edges.add(new ArrayList<>(Arrays.asList(3, 4)));         edges.add(new ArrayList<>(Arrays.asList(3, 5)));          graph = new ArrayList[n + 1];         for (int i = 1; i <= n; i++) {             graph[i] = new ArrayList<>();         }          for (ArrayList<Integer> edge : edges) {             int u = edge.get(0);             int v = edge.get(1);             graph[u].add(v);             graph[v].add(u);         }          subtree = new int[n + 1];         processed = new boolean[n + 1];         bit = new long[n + 1];          update(0, 1);         centroidDecomp(1);          System.out.println(ans); // Output the final answer     } } //This code is contributed by Utkarsh. 
Python3
import sys  # Adjacency list representation of the tree graph = [[] for _ in range(200001)]  # Size of subtree rooted at each node subtree = [0] * 200001  # ans stores the final answer, bit is for Fenwick tree bit = [0] * 200001  # Maximum depth encountered during centroid decomposition mx_depth = 0  # To mark nodes as processed during centroid decomposition processed = [False] * 200001  # Function to calculate subtree sizes rooted at each node def get_subtree_sizes(node, parent=0):     subtree[node] = 1     for i in graph[node]:         if not processed[i] and i != parent:             subtree[node] += get_subtree_sizes(i, node)     return subtree[node]  # Function to find the centroid of a subtree def get_centroid(desired, node, parent=0):     for i in graph[node]:         if not processed[i] and i != parent and subtree[i] >= desired:             return get_centroid(desired, i, node)     return node  # Function to update Fenwick tree def update(pos, val):     while pos <= n:         bit[pos] += val         pos += pos & -pos  # Function to query Fenwick tree for sum in a range def query(l, r):     ans = 0     while r:         ans += bit[r]         r -= r & -r     while l:         ans -= bit[l]         l -= l & -l     return ans  # Function to count paths in a subtree within a certain depth range def get_cnt(node, parent, filling, depth=1):     global mx_depth, ans     if depth > b:         return     mx_depth = max(mx_depth, depth)     if filling:         update(depth, 1)     else:         ans += query(max(0, a - depth), b - depth)     for i in graph[node]:         if not processed[i] and i != parent:             get_cnt(i, node, filling, depth + 1)  # Centroid decomposition of the tree def centroid_decomp(node=1):     global mx_depth     centroid = get_centroid(get_subtree_sizes(node) >> 1, node)     processed[centroid] = True     mx_depth = 0     for i in graph[centroid]:         if not processed[i]:             get_cnt(i, centroid, False)             get_cnt(i, centroid, True)     for i in range(1, mx_depth + 1):         update(i, -query(i, i))     for i in graph[centroid]:         if not processed[i]:             centroid_decomp(i)  # Static input n = 5 a = 1 b = 4 edges = [[1, 2], [2, 3], [3, 4], [3, 5]]  for u, v in edges:     graph[u].append(v)     graph[v].append(u)  # Final answer ans = 0 centroid_decomp() print(ans)  # This code is contributed by Ayush Mishra 
JavaScript
// Initialize global variables let n, a, b; let graph = new Array(200001); let subtree = new Array(200001).fill(0); let ans = 0; let bit = new Array(200001).fill(0); let mx_depth; let processed = new Array(200001).fill(false);  // Function to calculate subtree sizes rooted at each node function get_subtree_sizes(node, parent = 0) {     subtree[node] = 1;     for (let i of graph[node]) {         if (!processed[i] && i !== parent) {             subtree[node] += get_subtree_sizes(i, node);         }     }     return subtree[node]; }  // Function to find the centroid of a subtree function get_centroid(desired, node, parent = 0) {     for (let i of graph[node]) {         if (!processed[i] && i !== parent && subtree[i] >= desired) {             return get_centroid(desired, i, node);         }     }     return node; }  // Function to update Fenwick tree function update(pos, val) {     for (pos++; pos <= n; pos += pos & -pos) {         bit[pos] += val;     } }  // Function to query Fenwick tree for sum in a range function query(l, r) {     let ans = 0;     for (r++; r; r -= r & -r) {         ans += bit[r];     }     for (; l; l -= l & -l) {         ans -= bit[l];     }     return ans; }  // Function to count paths in a subtree within a certain depth range function get_cnt(node, parent, filling, depth = 1) {     if (depth > b) {         return;     }     mx_depth = Math.max(mx_depth, depth);     if (filling) {         update(depth, 1);     } else {         ans += query(Math.max(0, a - depth), b - depth);     }     for (let i of graph[node]) {         if (!processed[i] && i !== parent) {             get_cnt(i, node, filling, depth + 1);         }     } }  // Centroid decomposition of the tree function centroid_decomp(node = 1) {     let centroid = get_centroid(get_subtree_sizes(node) >> 1, node);     processed[centroid] = true;     mx_depth = 0;     for (let i of graph[centroid]) {         if (!processed[i]) {             get_cnt(i, centroid, false);             get_cnt(i, centroid, true);         }     }     for (let i = 1; i <= mx_depth; i++) {         update(i, -query(i, i));     }     for (let i of graph[centroid]) {         if (!processed[i]) {             centroid_decomp(i);         }     } }  // Main function function main() {     // Static input     n = 5;     a = 1; // or K1     b = 4; // or K2     let edges = [[1, 2], [2, 3], [3, 4], [3, 5]];      for (let i = 1; i <= n; i++) {         graph[i] = [];     }      for (let i = 0; i < edges.length; i++) {         let u = edges[i][0];         let v = edges[i][1];          graph[u].push(v);         graph[v].push(u);     }      // Initialize Fenwick tree with root node     update(0, 1);      // Perform centroid decomposition     centroid_decomp();      // Output the final answer     console.log(ans); }  // Invoke the main function main(); 

Output
10

Time complexity: O(N log N)
Auxiliary space: O(N) + O(log N)



Next Article
CSES Solutions - Fixed-Length Paths II

A

anshu_1230
Improve
Article Tags :
  • Graph
  • DSA
  • Binary Indexed Tree
  • CSES Problems
Practice Tags :
  • Graph

Similar Reads

    CSES Solutions - Grid Paths
    There are 88418 paths in a 7x7 grid from the upper-left square to the lower-left square. Each path corresponds to a 48-character description consisting of characters D (down), U (up), L (left) and R (right). You are given a description of a path which may also contain characters ? (any direction). Y
    15 min read
    CSES Solutions – Labyrinth
    You are given a map of a labyrinth, and your task is to find a path from start to end. You can walk left, right, up and down. The first input line has two integers n and m: the height and width of the map. Then there are lines of m characters describing the labyrinth. Each character is . (floor), #
    11 min read
    Maximum Ways to Cross the field
    Given a field in the shape of a (m x n) grid, with a car initially positioned at the coordinates [row, column]. You have the ability to move the car to one of the four adjacent cells in the field, possibly crossing the field's boundaries. You are limited to a maximum of maxlocomote moves for the car
    11 min read
    Valid paths in a grid in Python
    Given a 2D grid of 0s (obstacles) and 1s (valid paths), find the number of valid paths from the top-left corner to the bottom-right corner. You can only move down or right. Examples: Input: grid = [ [1, 1, 1], [1, 0, 1], [1, 1, 1]]Output: 2 Input: grid = [ [1, 1], [1, 1]]Output: 1 Valid paths in a g
    5 min read
    Grid Unique Paths - Count Paths in matrix
    Given an matrix of size m x n, the task is to find the count of all unique possible paths from top left to the bottom right with the constraints that from each cell we can either move only to the right or down.Examples: Input: m = 2, n = 2Output: 2Explanation: There are two paths(0, 0) -> (0, 1)
    15+ min read
geeksforgeeks-footer-logo
Corporate & Communications Address:
A-143, 7th Floor, Sovereign Corporate Tower, Sector- 136, Noida, Uttar Pradesh (201305)
Registered Address:
K 061, Tower K, Gulshan Vivante Apartment, Sector 137, Noida, Gautam Buddh Nagar, Uttar Pradesh, 201305
GFG App on Play Store GFG App on App Store
Advertise with us
  • Company
  • About Us
  • Legal
  • Privacy Policy
  • In Media
  • Contact Us
  • Advertise with us
  • GFG Corporate Solution
  • Placement Training Program
  • Languages
  • Python
  • Java
  • C++
  • PHP
  • GoLang
  • SQL
  • R Language
  • Android Tutorial
  • Tutorials Archive
  • DSA
  • Data Structures
  • Algorithms
  • DSA for Beginners
  • Basic DSA Problems
  • DSA Roadmap
  • Top 100 DSA Interview Problems
  • DSA Roadmap by Sandeep Jain
  • All Cheat Sheets
  • Data Science & ML
  • Data Science With Python
  • Data Science For Beginner
  • Machine Learning
  • ML Maths
  • Data Visualisation
  • Pandas
  • NumPy
  • NLP
  • Deep Learning
  • Web Technologies
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • ReactJS
  • NextJS
  • Bootstrap
  • Web Design
  • Python Tutorial
  • Python Programming Examples
  • Python Projects
  • Python Tkinter
  • Python Web Scraping
  • OpenCV Tutorial
  • Python Interview Question
  • Django
  • Computer Science
  • Operating Systems
  • Computer Network
  • Database Management System
  • Software Engineering
  • Digital Logic Design
  • Engineering Maths
  • Software Development
  • Software Testing
  • DevOps
  • Git
  • Linux
  • AWS
  • Docker
  • Kubernetes
  • Azure
  • GCP
  • DevOps Roadmap
  • System Design
  • High Level Design
  • Low Level Design
  • UML Diagrams
  • Interview Guide
  • Design Patterns
  • OOAD
  • System Design Bootcamp
  • Interview Questions
  • Inteview Preparation
  • Competitive Programming
  • Top DS or Algo for CP
  • Company-Wise Recruitment Process
  • Company-Wise Preparation
  • Aptitude Preparation
  • Puzzles
  • School Subjects
  • Mathematics
  • Physics
  • Chemistry
  • Biology
  • Social Science
  • English Grammar
  • Commerce
  • World GK
  • GeeksforGeeks Videos
  • DSA
  • Python
  • Java
  • C++
  • Web Development
  • Data Science
  • CS Subjects
@GeeksforGeeks, Sanchhaya Education Private Limited, All rights reserved
We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Cookie Policy & Privacy Policy
Lightbox
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
geeksforgeeks-suggest-icon
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.
geeksforgeeks-improvement-icon
Suggest Changes
min 4 words, max Words Limit:1000

Thank You!

Your suggestions are valuable to us.

What kind of Experience do you want to share?

Interview Experiences
Admission Experiences
Career Journeys
Work Experiences
Campus Experiences
Competitive Exam Experiences