Count Path Visits for Each Node for Given Path Queries
Last Updated : 3 Oct, 2026
A tree has n nodes numbered 1 to n, connected by n - 1 edges given as edges[][], where edges[i] = [u, v] indicates a direct edge between nodes u and v.
You are also given queries[][], where each query [u, v] represents the unique path from node u to node v. Every node on this path ( including u and v) is counted once.
For each node, find how many times it was counted across all queries in queries[][].
Note: The tree is connected and acyclic, with exactly n - 1 edges.
[Naive Approach] Traverse the Path for Every Query - O(n * q) Time and O(n) Space
The idea is to process each query independently by finding the unique path between its two given nodes. Once the path is found, increment the count of every node on it.
Since a tree has exactly one path between any two nodes, we use DFS to locate the path and update the corresponding node counts.
Working of the Approach:
Build an adjacency list to represent the tree.
For each query (u, v), run DFS from u to find the path to v.
While backtracking, identify the nodes that belong to the path and increment their counts.
After processing all queries, return the count of every node.
C++
#includeusingnamespacestd;vector<int>countVisits(intn,vector<vector<int>>&edges,vector<vector<int>>&queries){vector<vector<int>>adj(n+1);for(auto&edge:edges){intu=edge[0];intv=edge[1];adj[u].push_back(v);adj[v].push_back(u);}vector<int>ans(n+1,0);for(auto&query:queries){intu=query[0];intv=query[1];vector<int>parent(n+1,-1);queue<int>q;q.push(u);parent[u]=0;// Find the path from u to v using BFS.while(!q.empty()){intnode=q.front();q.pop();if(node==v)break;for(intnext:adj[node]){if(parent[next]==-1){parent[next]=node;q.push(next);}}}// Move from v back to u and count every path node.intnode=v;while(node!=0){ans[node]++;node=parent[node];}}ans.erase(ans.begin());returnans;}intmain(){intn=5;vector<vector<int>>edges={{1,2},{1,3},{3,4},{3,5}};vector<vector<int>>queries={{1,3},{2,5},{1,4}};vector<int>res=countVisits(n,edges,queries);cout<<"[";for(inti=0;i<res.size();i++){if(i>0)cout<<", ";cout<<res[i];}cout<<"]";return0;}
Java
importjava.util.ArrayDeque;importjava.util.ArrayList;classGFG{staticArrayList<Integer>countVisits(intn,int[][]edges,int[][]queries){ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<=n;i++){adj.add(newArrayList<>());}for(int[]edge:edges){intu=edge[0];intv=edge[1];adj.get(u).add(v);adj.get(v).add(u);}int[]ans=newint[n+1];for(int[]query:queries){intu=query[0];intv=query[1];int[]parent=newint[n+1];for(inti=0;i<=n;i++){parent[i]=-1;}ArrayDeque<Integer>q=newArrayDeque<>();q.add(u);parent[u]=0;// Find the path from u to v using BFS.while(!q.isEmpty()){intnode=q.poll();if(node==v)break;for(intnext:adj.get(node)){if(parent[next]==-1){parent[next]=node;q.add(next);}}}// Move from v back to u and count every path node.intnode=v;while(node!=0){ans[node]++;node=parent[node];}}ArrayList<Integer>res=newArrayList<>();for(inti=1;i<=n;i++){res.add(ans[i]);}returnres;}publicstaticvoidmain(String[]args){intn=5;int[][]edges={{1,2},{1,3},{3,4},{3,5}};int[][]queries={{1,3},{2,5},{1,4}};ArrayList<Integer>res=countVisits(n,edges,queries);System.out.println(res);}}
Python
fromcollectionsimportdequedefcountVisits(n,edges,queries):adj=[[]for_inrange(n+1)]foru,vinedges:adj[u].append(v)adj[v].append(u)ans=[0]*(n+1)foru,vinqueries:parent=[-1]*(n+1)q=deque([u])parent[u]=0# Find the path from u to v using BFS.whileq:node=q.popleft()ifnode==v:breakfornextNodeinadj[node]:ifparent[nextNode]==-1:parent[nextNode]=nodeq.append(nextNode)# Move from v back to u and count every path node.node=vwhilenode!=0:ans[node]+=1node=parent[node]returnans[1:]if__name__=="__main__":n=5edges=[[1,2],[1,3],[3,4],[3,5]]queries=[[1,3],[2,5],[1,4]]print(countVisits(n,edges,queries))
C#
usingSystem;usingSystem.Collections.Generic;classGFG{staticList<int>countVisits(intn,int[][]edges,int[][]queries){List<List<int>>adj=newList<List<int>>();for(inti=0;i<=n;i++){adj.Add(newList<int>());}foreach(int[]edgeinedges){intu=edge[0];intv=edge[1];adj[u].Add(v);adj[v].Add(u);}int[]ans=newint[n+1];foreach(int[]queryinqueries){intu=query[0];intv=query[1];int[]parent=newint[n+1];Array.Fill(parent,-1);Queue<int>q=newQueue<int>();q.Enqueue(u);parent[u]=0;// Find the path from u to v using BFS.while(q.Count>0){intnode=q.Dequeue();if(node==v)break;foreach(intnextinadj[node]){if(parent[next]==-1){parent[next]=node;q.Enqueue(next);}}}// Move from v back to u and count every path node.intcurrent=v;while(current!=0){ans[current]++;current=parent[current];}}List<int>res=newList<int>();for(inti=1;i<=n;i++){res.Add(ans[i]);}returnres;}publicstaticvoidMain(){intn=5;int[][]edges={newint[]{1,2},newint[]{1,3},newint[]{3,4},newint[]{3,5}};int[][]queries={newint[]{1,3},newint[]{2,5},newint[]{1,4}};List<int>res=countVisits(n,edges,queries);Console.WriteLine("["+string.Join(", ",res)+"]");}}
JavaScript
functioncountVisits(n,edges,queries){constadj=Array.from({length:n+1},()=>[]);for(const[u,v]ofedges){adj[u].push(v);adj[v].push(u);}constans=newArray(n+1).fill(0);for(const[u,v]ofqueries){constparent=newArray(n+1).fill(-1);constqueue=[u];letfront=0;parent[u]=0;// Find the path from u to v using BFS.while(front<queue.length){constnode=queue[front++];if(node===v)break;for(constnextofadj[node]){if(parent[next]===-1){parent[next]=node;queue.push(next);}}}// Move from v back to u and count every path node.letnode=v;while(node!==0){ans[node]++;node=parent[node];}}returnans.slice(1);}// Driver Codeconstn=5;constedges=[[1,2],[1,3],[3,4],[3,5]];constqueries=[[1,3],[2,5],[1,4]];constres=countVisits(n,edges,queries);console.log("["+res.join(", ")+"]");
Output
[3, 1, 3, 1, 1]
[Expected Approach] Mark Paths with LCA and Tree Difference Array - O((n + q) log n) Time and O(n log n) Space
The idea is to preprocess the tree for LCA queries using binary lifting, then use a tree difference array to mark the endpoints and LCA of each path.
After processing all queries, one bottom-up traversal accumulates these values to obtain the number of times each node lies on a queried path.
Working of the Approach:
Root the tree and compute depth[], parent[], and the binary lifting table for every node.
For each query (u, v), find lca, then update diff[u]++, diff[v]++, diff[lca]--, and diff[parent[lca]]-- when parent[lca] exists.
Traverse the tree from leaves towards the root and add each node's diff value to its parent.
After this accumulation, diff[i] gives the number of queried paths that pass through node i.
Compute the LCA of each query: LCA(1, 3) = 1, LCA(2, 5) = 1, and LCA(1, 4) = 1.
For query [1, 3], update diff[1] += 1, diff[3] += 1, and diff[1] -= 1. This marks the path 1 -> 3.
For query [2, 5], update diff[2] += 1, diff[5] += 1, and diff[1] -= 1. This marks the path 2 -> 1 -> 3 -> 5.
For query [1, 4], update diff[1] += 1, diff[4] += 1, and diff[1] -= 1. This marks the path 1 -> 3 -> 4.
After processing all queries, accumulate diff[] from children to parents: node 4 contributes to 3, node 5 contributes to 3, and nodes 2 and 3 contribute to 1.
The final values become [3, 1, 3, 1, 1], which are exactly the number of times each node appears on the queried paths.
C++
#includeusingnamespacestd;vector<int>countVisits(intn,vector<vector<int>>&edges,vector<vector<int>>&queries){intLOG=1;while((1<<LOG)<=n)LOG++;vector<vector<int>>adj(n+1);for(auto&edge:edges){intu=edge[0];intv=edge[1];adj[u].push_back(v);adj[v].push_back(u);}vector<vector<int>>up(LOG,vector<int>(n+1));vector<int>depth(n+1);vector<int>order;order.reserve(n);// Build parent, depth and traversal order from the root.queue<int>q;q.push(1);up[0][1]=0;while(!q.empty()){intnode=q.front();q.pop();order.push_back(node);for(intnext:adj[node]){if(next==up[0][node])continue;up[0][next]=node;depth[next]=depth[node]+1;q.push(next);}}// Build the binary lifting table.for(intj=1;j<LOG;j++){for(intnode=1;node<=n;node++){up[j][node]=up[j-1][up[j-1][node]];}}autolca=[&](intu,intv){if(depth[u]<depth[v])swap(u,v);intdiffDepth=depth[u]-depth[v];for(intj=0;j<LOG;j++){if(diffDepth&(1<<j))u=up[j][u];}if(u==v)returnu;for(intj=LOG-1;j>=0;j--){if(up[j][u]!=up[j][v]){u=up[j][u];v=up[j][v];}}returnup[0][u];};vector<int>diff(n+1,0);for(auto&query:queries){intu=query[0];intv=query[1];intancestor=lca(u,v);// Mark the endpoints and remove the contribution above the LCA.diff[u]++;diff[v]++;diff[ancestor]--;if(up[0][ancestor]!=0)diff[up[0][ancestor]]--;}// Accumulate child contributions towards the root.for(inti=n-1;i>0;i--){intnode=order[i];diff[up[0][node]]+=diff[node];}diff.erase(diff.begin());returndiff;}intmain(){intn=5;vector<vector<int>>edges={{1,2},{1,3},{3,4},{3,5}};vector<vector<int>>queries={{1,3},{2,5},{1,4}};vector<int>res=countVisits(n,edges,queries);cout<<"[";for(inti=0;i<res.size();i++){if(i>0)cout<<", ";cout<<res[i];}cout<<"]";return0;}
Java
importjava.util.ArrayDeque;importjava.util.ArrayList;importjava.util.Arrays;classGFG{staticArrayList<Integer>countVisits(intn,int[][]edges,int[][]queries){intLOG=1;while((1<<LOG)<=n)LOG++;ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<=n;i++)adj.add(newArrayList<>());for(int[]edge:edges){intu=edge[0];intv=edge[1];adj.get(u).add(v);adj.get(v).add(u);}int[][]up=newint[LOG][n+1];int[]depth=newint[n+1];int[]order=newint[n];intorderSize=0;ArrayDeque<Integer>q=newArrayDeque<>();q.add(1);// Build parent, depth and traversal order from the root.while(!q.isEmpty()){intnode=q.poll();order[orderSize++]=node;for(intnext:adj.get(node)){if(next==up[0][node])continue;up[0][next]=node;depth[next]=depth[node]+1;q.add(next);}}// Build the binary lifting table.for(intj=1;j<LOG;j++){for(intnode=1;node<=n;node++){up[j][node]=up[j-1][up[j-1][node]];}}int[]diff=newint[n+1];for(int[]query:queries){intu=query[0];intv=query[1];intancestor=findLca(u,v,depth,up,LOG);// Mark the endpoints and remove the contribution above the LCA.diff[u]++;diff[v]++;diff[ancestor]--;if(up[0][ancestor]!=0)diff[up[0][ancestor]]--;}// Accumulate child contributions towards the root.for(inti=orderSize-1;i>0;i--){intnode=order[i];diff[up[0][node]]+=diff[node];}ArrayList<Integer>res=newArrayList<>();for(inti=1;i<=n;i++)res.add(diff[i]);returnres;}staticintfindLca(intu,intv,int[]depth,int[][]up,intLOG){if(depth[u]<depth[v]){inttemp=u;u=v;v=temp;}intdiffDepth=depth[u]-depth[v];for(intj=0;j<LOG;j++){if((diffDepth&(1<<j))!=0)u=up[j][u];}if(u==v)returnu;for(intj=LOG-1;j>=0;j--){if(up[j][u]!=up[j][v]){u=up[j][u];v=up[j][v];}}returnup[0][u];}publicstaticvoidmain(String[]args){intn=5;int[][]edges={{1,2},{1,3},{3,4},{3,5}};int[][]queries={{1,3},{2,5},{1,4}};ArrayList<Integer>res=countVisits(n,edges,queries);System.out.println(res);}}
Python
fromcollectionsimportdequedefcountVisits(n,edges,queries):LOG=n.bit_length()adj=[[]for_inrange(n+1)]foru,vinedges:adj[u].append(v)adj[v].append(u)up=[[0]*(n+1)for_inrange(LOG)]depth=[0]*(n+1)order=[]q=deque([1])# Build parent, depth and traversal order from the root.whileq:node=q.popleft()order.append(node)fornext_nodeinadj[node]:ifnext_node==up[0][node]:continueup[0][next_node]=nodedepth[next_node]=depth[node]+1q.append(next_node)# Build the binary lifting table.forjinrange(1,LOG):fornodeinrange(1,n+1):up[j][node]=up[j-1][up[j-1][node]]deffindLca(u,v):ifdepth[u]<depth[v]:u,v=v,udiff_depth=depth[u]-depth[v]forjinrange(LOG):ifdiff_depth&(1<<j):u=up[j][u]ifu==v:returnuforjinrange(LOG-1,-1,-1):ifup[j][u]!=up[j][v]:u=up[j][u]v=up[j][v]returnup[0][u]diff=[0]*(n+1)foru,vinqueries:ancestor=findLca(u,v)# Mark the endpoints and remove the contribution above the LCA.diff[u]+=1diff[v]+=1diff[ancestor]-=1ifup[0][ancestor]!=0:diff[up[0][ancestor]]-=1# Accumulate child contributions towards the root.fornodeinreversed(order[1:]):diff[up[0][node]]+=diff[node]returndiff[1:]if__name__=="__main__":n=5edges=[[1,2],[1,3],[3,4],[3,5]]queries=[[1,3],[2,5],[1,4]]print(countVisits(n,edges,queries))
C#
usingSystem;usingSystem.Collections.Generic;classGFG{staticList<int>countVisits(intn,int[][]edges,int[][]queries){intLOG=1;while((1<<LOG)<=n)LOG++;List<List<int>>adj=newList<List<int>>();for(inti=0;i<=n;i++)adj.Add(newList<int>());foreach(int[]edgeinedges){intu=edge[0];intv=edge[1];adj[u].Add(v);adj[v].Add(u);}int[,]up=newint[LOG,n+1];int[]depth=newint[n+1];int[]order=newint[n];intorderSize=0;Queue<int>q=newQueue<int>();q.Enqueue(1);// Build parent, depth and traversal order from the root.while(q.Count>0){intnode=q.Dequeue();order[orderSize++]=node;foreach(intnextinadj[node]){if(next==up[0,node])continue;up[0,next]=node;depth[next]=depth[node]+1;q.Enqueue(next);}}// Build the binary lifting table.for(intj=1;j<LOG;j++){for(intnode=1;node<=n;node++){up[j,node]=up[j-1,up[j-1,node]];}}int[]diff=newint[n+1];foreach(int[]queryinqueries){intu=query[0];intv=query[1];intancestor=findLca(u,v,depth,up,LOG);// Mark the endpoints and remove the contribution above the LCA.diff[u]++;diff[v]++;diff[ancestor]--;if(up[0,ancestor]!=0)diff[up[0,ancestor]]--;}// Accumulate child contributions towards the root.for(inti=orderSize-1;i>0;i--){intnode=order[i];diff[up[0,node]]+=diff[node];}List<int>res=newList<int>();for(inti=1;i<=n;i++)res.Add(diff[i]);returnres;}staticintfindLca(intu,intv,int[]depth,int[,]up,intLOG){if(depth[u]<depth[v]){inttemp=u;u=v;v=temp;}intdiffDepth=depth[u]-depth[v];for(intj=0;j<LOG;j++){if((diffDepth&(1<<j))!=0)u=up[j,u];}if(u==v)returnu;for(intj=LOG-1;j>=0;j--){if(up[j,u]!=up[j,v]){u=up[j,u];v=up[j,v];}}returnup[0,u];}publicstaticvoidMain(){intn=5;int[][]edges={newint[]{1,2},newint[]{1,3},newint[]{3,4},newint[]{3,5}};int[][]queries={newint[]{1,3},newint[]{2,5},newint[]{1,4}};List<int>res=countVisits(n,edges,queries);Console.WriteLine("["+string.Join(", ",res)+"]");}}
JavaScript
functioncountVisits(n,edges,queries){letLOG=1;while((1<<LOG)<=n)LOG++;constadj=Array.from({length:n+1},()=>[]);for(const[u,v]ofedges){adj[u].push(v);adj[v].push(u);}constup=Array.from({length:LOG},()=>newArray(n+1).fill(0));constdepth=newArray(n+1).fill(0);constorder=[];constqueue=[1];letfront=0;// Build parent, depth and traversal order from the root.while(front<queue.length){constnode=queue[front++];order.push(node);for(constnextofadj[node]){if(next===up[0][node])continue;up[0][next]=node;depth[next]=depth[node]+1;queue.push(next);}}// Build the binary lifting table.for(letj=1;j<LOG;j++){for(letnode=1;node<=n;node++){up[j][node]=up[j-1][up[j-1][node]];}}functionfindLca(u,v){if(depth[u]<depth[v]){[u,v]=[v,u];}letdiffDepth=depth[u]-depth[v];for(letj=0;j<LOG;j++){if(diffDepth&(1<<j)){u=up[j][u];}}if(u===v)returnu;for(letj=LOG-1;j>=0;j--){if(up[j][u]!==up[j][v]){u=up[j][u];v=up[j][v];}}returnup[0][u];}constdiff=newArray(n+1).fill(0);for(const[u,v]ofqueries){constancestor=findLca(u,v);// Mark the endpoints and remove the contribution above the LCA.diff[u]++;diff[v]++;diff[ancestor]--;if(up[0][ancestor]!==0){diff[up[0][ancestor]]--;}}// Accumulate child contributions towards the root.for(leti=order.length-1;i>0;i--){constnode=order[i];diff[up[0][node]]+=diff[node];}returndiff.slice(1);}// Driver Codeconstn=5;constedges=[[1,2],[1,3],[3,4],[3,5]];constqueries=[[1,3],[2,5],[1,4]];constres=countVisits(n,edges,queries);console.log("["+res.join(", ")+"]");