Path containing K Nodes
![]() |
All submissions for this problem are available.
Read problems statements in Mandarin Chinese and Russian as well.
You are given a tree.
You have to execute numerous queries on this tree. In a query, you will be given K nodes and you need to find if there is a path in the tree which contains all these K nodes.
If there is a path containing these K nodes, then output Yes. Otherwise, output No.
Input
First line contains T, number of test cases to follow.
First line of each test case contains an integer N which represents the number of nodes in the tree.
Next N-1 lines contain the description of the tree. Each line contains 2 space separated integers implying that there is an edge between these two nodes.
Next line contains Q, number of path queries to follow.
First line of each query contains an integer K.
Second line contains K space separated nodes.
Output
For each query, output Yes if there is a path containing the K query nodes. Otherwise, output No.
Constraints
- 1 ≤ N ≤ 105
- 1 ≤ Sum of N over all test cases ≤ 105
- 1 ≤ T ≤ 500
- 3 ≤ K ≤ N
- 1 ≤ Sum of K over all test cases and queries ≤ 106
- Nodes are numbered from 1
Example
Input: 1 10 3 1 5 7 4 6 10 4 8 9 2 1 3 4 8 5 5 3 4 3 8 10 3 4 8 7 9 6 3 2 1 6 3 6 2 5 Output: Yes No Yes No
Explanation:
Query 1: The path corresponding to it is 8->5->3->4->10.
Query 2: There does not exists any path joining all 4.
Quick Explanation:
We will try building a path to solve this problem. A path will have end points and we will first try to find out these two end points (say and ) and then try to check if all the nodes lie either on the path from to the root or from to root.
Now, if the above conditions are satisfied, we need to check whether they still form a pair or not. Solution contains a detailed explanation of the approach.
Solution:
Fix any node as root of the tree. Then do a depth-first traversal and store 3 things for each node:
- Depth of the node : It is the distance of the node from the root.
- Start time of the dfs : It is the time when the dfs started on the node.
- End time of the dfs : It is the time when the dfs ended on the node.
You can increase time by when moving to an unvisited node.
Now for all the given nodes, find the deepest node and the node closest to root.
Let the deepest node be and let the node closest to root be .
We will now partition the set of nodes into two disjoint sets and .
Set will contain nodes which are on the path from root to . Set will contain the remaining nodes.
How to make set ?
If the start time of node is before the start time of node and the end time of node is after the end time of node then node belongs to set . [Using properties of DFS]
If set was a null set, then our answer is "Yes".
Find the deepest node in the set , let us name it as . [Deepest node in the remaining nodes/set ]
Now again follow the same procedure to partition the set into and where set contains nodes from set which are on the path from to root of the tree.
If set is not empty, then our answer is "No". ( Reasons ? : I hope the readers to use pen and paper to draw a diagram and understand how things are moving, from there it will be trivial to find the reason)
Now, Find the LCA of and . Let us call this node as .
must lie between (smallest depth node in nodes) and root of the tree for a valid path to exists.
Reason:
If lies in between root and , then there does not exist any path.
must be repeated twice in the journey from to . Hence not a path.
Time complexity of this algorithm is (for dfs part per test case) + (per query).
****************** THE CODE GOES HERE **************************************************
#include<bits/stdc++.h>
using namespace std;
list<int> arr[100010];
#define mp make_pair
#define pb push_back
#define ff first
#define ss second
int tmi=0;
int level[100010];
int T[100010];
int dp[100010][25];
int n;
int sttime[100010];
int ettime[100010];
void pre()
{
memset(dp,-1,sizeof(dp));
//cout<<"here "<<endl;
for(int i=1;i<=n;i++)
{
dp[i][0]=T[i];
// cout<<"set oth ancestor of "<<i<<" as "<<T[i]<<endl;
}
for(int j=1;1<<j<=n;j++)
{
for(int i=1;i<=n;i++)
{
if(dp[i][j-1]!=-1)
{
dp[i][j]=dp[dp[i][j-1]][j-1];
}
}
}
}
int flca(int p, int q)
{
//cout<<"levels "<<level[p]<<" "<<level[q]<<endl;
if(level[p]<level[q])
{
swap(p,q);
}
int log;
for(log=1;(1<<log)<=level[p];log++);
log--;
for (int i = log; i >= 0; i--)
if (level[p] - (1 << i) >= level[q])
p = dp[p][i];
if (p == q)
return p;
// cout<<"log is "<<log<<endl;
for (int i = log; i >= 0; i--)
{
// cout<<"to chek "<<i<<" th ancestor of "<<p<<" "<<q<<" they are "<<dp[p][i]<<" "<<dp[q][i]<<endl;
if (dp[p][i] != -1 && dp[p][i] != dp[q][i])
{
p = dp[p][i], q = dp[q][i];
// cout<<"change p q to "<<p<<" "<<q<<endl;
}
}
return T[p];
}
void dfs(int root,int par,int lev)
{
level[root]=lev;
sttime[root]=tmi;
T[root]=par;
list<int> ::iterator it;
for(it=arr[root].begin();it!=arr[root].end();it++)
{
if(*it!=par)
{
tmi++;
dfs(*it,root,lev+1);
}
}
ettime[root]=tmi;
}
bool ischild(int ch,int an)
{
if(sttime[ch]>=sttime[an] && ettime[ch]<=ettime[an])
return 1;
return 0;
}
int main()
{
int t;
cin>>t;
while(t--)
{
//int n;
tmi=0;
cin>>n;
for(int i=1;i<=n;i++)
arr[i].clear();
for(int i=0;i<n-1;i++)
{
int aa,bb;
scanf("%d %d",&aa,&bb);
arr[aa].pb(bb);
arr[bb].pb(aa);
}
dfs(1,0,0);
pre();
int q;
cin>>q;
while(q--)
{
int tt;
scanf("%d",&tt);
vector<int> v;
for(int i=0;i<tt;i++)
{
int aa;
scanf("%d",&aa);
v.pb(aa);
// mark[i]=0;
}
vector<int> a,b,c,d,e;
int lev=0;
int deep1=0;
int lvmi=1000000;
int sm=-1;
for(int i=0;i<tt;i++)
{
if(level[v[i]]>lev)
{
deep1=v[i];
lev=level[deep1];
}
if(level[v[i]]<lvmi)
{
sm=v[i];
lvmi=level[sm];
}
}
// cout<<"deep 1 "<<deep1<<endl;
for(int i=0;i<tt;i++)
{
int nd=v[i];
if(sttime[nd]<=sttime[deep1] && ettime[nd]>=ettime[deep1])
{
a.pb(nd);
// cout<<"in a "<<nd<<endl;
}
else
{
b.pb(nd);
}
}
if(b.size()==0)
{
printf("Yes\n");
continue;
}
int sz=b.size();
lev=0;
int deep2=-1;
for(int i=0;i<sz;i++)
{
int nd=b[i];
if(level[nd]>lev)
{
lev=level[nd];
deep2=nd;
}
}
for(int i=0;i<sz;i++)
{
int nd=b[i];
if(sttime[nd]<=sttime[deep2] && ettime[nd]>=ettime[deep2])
{
c.pb(nd);
// cout<<"in a "<<nd<<endl;
}
else
{
d.pb(nd);
}
}
if(d.size()!=0)
{
printf("No\n");
continue;
}
int res=c.size();
int lca=flca(deep2,deep1);
if(ischild(sm,lca))
{
printf("Yes\n");
}
else printf("No\n");
}
// cout<<"deep2 "<<deep2<<endl;
}
return 0;
}

No comments:
Post a Comment