• 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
    • 想想有没有可以优化的地方,一些条件自己有没有发掘到。
    • 遇到数路径问题一般都要用到lca,lca的运用很巧妙的.
  • 相关阅读:
    Nginx(ab性能测试)
    Nginx(配置域名后,不能配置到public目录原因)
    sublime text3的php代码合法检查
    Nginx(expires 缓存减轻服务端压力)
    Nginx(Gzip加速访问速度)
    Nginx(Rewrite语法)
    Nginx(location分析)
    Nginx(日志切割)
    Nginx(Logs)
    Java内部类——闭包与回调
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/16171670.html
Copyright © 2020-2023  润新知