1. 程式人生 > 其它 >Tree Queries(LCA)

Tree Queries(LCA)

You are given a rooted tree consisting of nn vertices numbered from 11 to nn. The root of the tree is a vertex number 11.

A tree is a connected undirected graph with n-1n−1 edges.

You are given mm queries. The ii-th query consists of the set of k_ik 
i
​
  distinct vertices v_i[1], v_i[2], \dots, v_i[k_i]v 
i
​
 [
1],v i ​ [2],…,v i ​ [k i ​ ]. Your task is to say if there is a path from the root to some vertex uu such that each of the given kk vertices is either belongs to this path or has the distance 11 to some vertex of this path. Input The first line of the input contains two integers nn and mm (2
\le n \le 2 \cdot 10^52≤n≤210 5 , 1 \le m \le 2 \cdot 10^51≤m≤210 5 ) — the number of vertices in the tree and the number of queries. Each of the next n-1n−1 lines describes an edge of the tree. Edge ii is denoted by two integers u_iu i ​ and v_iv i ​ , the labels of vertices it connects (1
\le u_i, v_i \le n, u_i \ne v_i(1≤u i ​ ,v i ​ ≤n,u i ​  =v i ​ ). It is guaranteed that the given edges form a tree. The next mm lines describe queries. The ii-th line describes the ii-th query and starts with the integer k_ik i ​ (1 \le k_i \le n1≤k i ​ ≤n) — the number of vertices in the current query. Then k_ik i ​ integers follow: v_i[1], v_i[2], \dots, v_i[k_i]v i ​ [1],v i ​ [2],…,v i ​ [k i ​ ] (1 \le v_i[j] \le n1≤v i ​ [j]≤n), where v_i[j]v i ​ [j] is the jj-th vertex of the ii-th query. It is guaranteed that all vertices in a single query are distinct. It is guaranteed that the sum of k_ik i ​ does not exceed 2 \cdot 10^5210 5 (\sum\limits_{i=1}^{m} k_i \le 2 \cdot 10^5 i=1 ∑ m ​ k i ​ ≤210 5 ). Output For each query, print the answer — "YES", if there is a path from the root to some vertex uu such that each of the given kk vertices is either belongs to this path or has the distance 11 to some vertex of this path and "NO" otherwise. Sample 1 Inputcopy Outputcopy 10 6 1 2 1 3 1 4 2 5 2 6 3 7 7 8 7 9 9 10 4 3 8 9 10 3 2 4 6 3 2 1 5 3 4 8 2 2 6 10 3 5 4 7 YES YES YES YES NO NO Note The picture corresponding to the example: Consider the queries. The first query is [3, 8, 9, 10][3,8,9,10]. The answer is "YES" as you can choose the path from the root 11 to the vertex u=10u=10. Then vertices [3, 9, 10][3,9,10] belong to the path from 11 to 1010 and the vertex 88 has distance 11 to the vertex 77 which also belongs to this path. The second query is [2, 4, 6][2,4,6]. The answer is "YES" as you can choose the path to the vertex u=2u=2. Then the vertex 44 has distance 11 to the vertex 11 which belongs to this path and the vertex 66 has distance 11 to the vertex 22 which belongs to this path. The third query is [2, 1, 5][2,1,5]. The answer is "YES" as you can choose the path to the vertex u=5u=5 and all vertices of the query belong to this path. The fourth query is [4, 8, 2][4,8,2]. The answer is "YES" as you can choose the path to the vertex u=9u=9 so vertices 22 and 44 both have distance 11 to the vertex 11 which belongs to this path and the vertex 88 has distance 11 to the vertex 77 which belongs to this path. The fifth and the sixth queries both have answer "NO" because you cannot choose suitable vertex uu.
View Problem

思路:

  • 反解法: 正著想(從1到其他節點不好想)就從其他節點到1,這樣就好想多了
  • 這條路徑一定是從 最深的那個點到1去的。
  • 最開始的思路就是: 述鏈剖分+線段樹,記錄走過的點,然後判斷其他的點或者他的父親是不是在這個路徑上
  • 但是這個寫法明顯複雜,於是應一個想法就是,求其他點和深度最深的那個點的Lca,看lca是不是那個點,或者是他的父親。
#include <bits/stdc++.h>
using namespace std;
#define ri register int 
#define M 200505

template <class G> void read(G &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return ;
}

vector <int> p[M];

int fa[M],dep[M],vis[M],sz[M],son[M];
void dfs1(int a,int f)
{
    fa[a]=f;vis[a]=1;
    dep[a]=dep[f]+1;
    sz[a]=1;
    int mz=0;
    for(ri i=0;i<p[a].size();i++)
    {
        int b=p[a][i];
        if(vis[b]) continue;
        dfs1(b,a);
        sz[a]+=sz[b];
        if(sz[b]>mz)
        {
            mz=sz[b];
            son[a]=b;
        }
    }
}
int top[M];
void dfs2(int a,int f)
{
    top[a]=f;vis[a]=1;
    if(son[a]) dfs2(son[a],f);
    for(ri i=0;i<p[a].size();i++)
    {
        int b=p[a][i];
        if(vis[b]) continue;
        dfs2(b,b);
    }
}
int n,m;
int val[M];
int lca(int a,int b)
{
    while(top[a]!=top[b])
    {
       if(dep[top[a]]<dep[top[b]]) swap(a,b);
       a=fa[top[a]];
    }
    if(dep[a]<dep[b]) swap(a,b);
    return b;
}
int main(){
    
    read(n);read(m);
    for(ri i=1;i<n;i++)
    {
        int a,b;
        read(a);read(b);
        p[a].push_back(b);
        p[b].push_back(a);
    }
    
    dfs1(1,1);
    memset(vis,0,sizeof(vis));
    dfs2(1,1);
    for(ri i=1;i<=m;i++)
    {
        int k;
        read(k);
        int tmp=0,mx=0;
        for(ri j=1;j<=k;j++)
        {
            read(val[j]);
            if(dep[val[j]]>mx) 
            {
               mx=dep[val[j]];
               tmp=val[j];
            }
        }
        int flag=1;
        for(ri j=1;j<=k;j++)
        {
            if(val[j]==tmp) continue;
            int a=lca(tmp,val[j]);
            if(a==val[j]||a==fa[val[j]]) continue;
            else {
                flag=0;break;
            }
        }
        if(flag) printf("YES\n");
        else printf("NO\n");
        
        
    }
    return 0;
    
}
View Code

後記:

  • 當你想出一個思路後,看看寫法複雜度,這個東西太高,不僅浪費時間和精力,還可能做不出來,完全是負val
  • 想想有沒有可以優化的地方,一些條件自己有沒有發掘到。