=Tree Queries CodeForces

题目大意:一棵树,然后m个询问,每个询问有k个点,然后判断是否有一条路,要求这k个点要么在这条路上,要么和这条路相距为1.

题解:刚开始的思路是这样的,这条路的终点肯定是深度最深的那个点,然后用BFS找到从1到终点的路线,然后在对路径上的点和与路径直接相连的点进行判断,看这k个点是否都在其中,然后就TLE了,为什么会T呢?当这棵树成了一条链时,那么算法的复杂度就退化为O(nm)。 我们来换种思路想一下,不变的还是终点,然后如果这k个点中的一些点在从1到终点的路上,那么终点和该点的LCA应该为深度小的那个点,如果与路径的距离为1 ,那么终点和该点的LCA应该是深度小的父亲节点。

code:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
vector<int>ve[N];
int dis[N];
int fa[N][30];
bool mark[N];
int arr[N];
int bits[32];
void inint(){
    bits[0]=1;
    for(int i=1;i<=29;i++) bits[i]=bits[i-1]<<1; 
}
void dfs(int x,int y){
    dis[x]=dis[y]+1;
    fa[x][0]=y;
    for(int i=1;i<=29;i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    for(int i=0;i<ve[x].size();i++){
        if(ve[x][i]!=y){
            dfs(ve[x][i],x);
        }
    }
}
int lca(int x,int y){
    if(dis[x]<dis[y]) swap(x,y);
    int dif=dis[x]-dis[y];
    for(int i=29;i>=0;i--){
        if(dif>=bits[i]) {
            dif-=bits[i];
            x=fa[x][i];
        }
    }
    if(x==y) return x;
    for(int i=29;i>=0;i--){
        if(dis[x]>=bits[i]&&fa[x][i]!=fa[y][i]){
            x=fa[x][i];y=fa[y][i];
        } 
    }
    return fa[x][0];
}
int main(){
    inint();
    int n,m;
    cin>>n>>m;
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        ve[x].push_back(y);
        ve[y].push_back(x);
    }
    dfs(1,0);
    int k,x;
    while(m--){
        cin>>k;
        int pos,depth=0;
        for(int i=1;i<=k;i++){
            cin>>arr[i];
            if(dis[arr[i]]>depth){
                depth=dis[arr[i]];
                pos=arr[i];
            }
        }
        bool flag=0;
        for(int i=1;i<=k;i++){
            int c=lca(pos,arr[i]);
            if(c==fa[arr[i]][0]||c==arr[i]){
                continue ;
            }
            else {
                flag=1;
                break;
            }
        }
        if(flag)cout<<"NO"<<endl;
        else puts("YES");
    } 
    
    return 0;
} 
原文地址:https://www.cnblogs.com/Accepting/p/12849633.html