Loading

CodeForces-1702G Passable Paths

Passable Paths

LCA

在树上找到形容一条链,只用找到链的两个端点即可,因此这题的初始想法就是找端点

第一个端点:深度最深的地方

第二个端点:离第一个端点最远的那个点

找到两个端点之后,就判断一下其他点是否在这个链上:最快的方法就是判断两个端点到这个点 p

的距离之和,是不是和链长相等

以上倍增 LCA 实现一下就好了,距离的话直接找到根的距离,也就是深度差,容斥一下算距离就好了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
vector<int>gra[maxn];
int dep[maxn], fa[maxn][25], pa[maxn];

void dfs(int now, int pre, int d)
{
    dep[now] = d;
    fa[now][0] = pre;
    for(auto nex : gra[now])
    {
        if(nex == pre) continue;
        dfs(nex, now, d + 1);
    }

}

void init(int n, int rt = 1)
{
    dfs(rt, rt, 0);
    for(int i=1; i<=20; i++)
        for(int j=1; j<=n; j++)
            fa[j][i] = fa[fa[j][i-1]][i-1];
}

int LCA(int a, int b)
{
    if(dep[a] < dep[b]) swap(a, b);
    int dif = dep[a] - dep[b];
    for(int i=20; i>=0; i--)
    {
        if(dif >= (1 << i))
        {
            dif -= 1 << i;
            a = fa[a][i];
        }
    }
    if(a == b) return a;
    for(int i=20; i>=0; i--)
    {
        if(fa[a][i] != fa[b][i])
        {
            a = fa[a][i];
            b = fa[b][i];
        }
    }
    return fa[a][0];
}

int dis(int a, int b)
{
    return dep[a] + dep[b] - 2 * dep[LCA(a, b)];
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i=1; i<n; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        gra[x].push_back(y);
        gra[y].push_back(x);
    }
    init(n);
    int m;
    scanf("%d", &m);
    while(m--)
    {
        int k;
        scanf("%d", &k);
        int d = -1, a = 0, b = 0, f = 1;
        for(int i=0; i<k; i++)
        {
            scanf("%d", &pa[i]);
            if(dep[pa[i]] > d) {a = pa[i]; d = dep[pa[i]];}
        }
        d = -1;
        for(int i=0; i<k; i++)
        {
            int x = dis(a, pa[i]);
            if(d < x)
            {
                b = pa[i];
                d = x;
            }
        }
        for(int i=0; i<k && f; i++)
        {
            if(dis(a, pa[i]) + dis(b, pa[i]) != d)
                f = 0;
        }
        printf("%s\n", f ? "yes" : "no");
        
    }
    return 0;
}

posted @ 2022-08-14 20:05  dgsvygd  阅读(30)  评论(0编辑  收藏  举报