Loading

CodeForces-1328E Tree Queries

Tree Queries

LCA 倍增 + 思维

所有的点到一条链的距离至多为 \(1\),代表他们的父节点一定都在同一条链上

根据这个,找到最深的点,然后判断所有的点和它是不是在同一个链:它与其他点的 LCA 都是等于其他点

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 10;
vector<int>gra[maxn];
int dep[maxn], fa[maxn][25];

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

void init(int n)
{
    dfs(1, 1, 1);
    for(int i=1; i<25; 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=24; i>=0; i--)
    {
        if(dif >= (1 << i))
        {
            dif -= 1 << i;
            a = fa[a][i];
        }
    }
    if(a == b) return a;
    for(int i=24; i>=0; i--)
    {
        if(fa[a][i] != fa[b][i])
        {
            a = fa[a][i];
            b = fa[b][i];
        }
    }
    return fa[a][0];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    cin >> n >> m;
    for(int i=1; i<n; i++)
    {
        int a, b;
        cin >> a >> b;
        gra[a].push_back(b);
        gra[b].push_back(a);
    }
    init(n);
    while(m--)
    {
        int k;
        cin >> k;
        vector<int>p(k);
        int dd = -1, pa = 0;
        for(int i=0; i<k; i++)
        {
            cin >> p[i];
            p[i] = fa[p[i]][0];
            if(dep[p[i]] > dd)
            {
                dd = dep[p[i]];
                pa = p[i];
            }
        }
        int f = 1;
        for(int i=0; i<k && f; i++)
        {
            if(LCA(pa, p[i]) != p[i])
                f = 0;
        }
        if(f) cout << "YES\n";
        else cout << "NO\n";
    }
    cout << endl;
    return 0;
}

也可以用 \(dfs\) 序来判断是否在同一条链:找到 \(dfs\) 序最深的那个点,然后判断其他点是不是其祖先,如果都是证明是同一条链

时间复杂度 \(O(n + \sum k)\)

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 10;
vector<int>gra[maxn];
int dep[maxn], in[maxn], out[maxn], fa[maxn];

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

bool is_anc(int u, int v)
{
    return in[u] <= in[v] && out[v] <= out[u];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    cin >> n >> m;
    for(int i=1; i<n; i++)
    {
        int a, b;
        cin >> a >> b;
        gra[a].push_back(b);
        gra[b].push_back(a);
    }
    dfs(1, 1, 1);
    while(m--)
    {
        int k;
        cin >> k;
        vector<int>p(k);
        int pb = -1;
        for(int i=0; i<k; i++)
        {
            cin >> p[i];
            p[i] = fa[p[i]];
            if(pb == -1 || out[pb] > out[p[i]]) pb = p[i];
        }
        int f = 1;
        for(int i=0; i<k && f; i++)
        {
            if(!is_anc(p[i], pb))
                f = 0;
        }
        if(f) cout << "YES\n";
        else cout << "NO\n";
    }
    cout << endl;
    return 0;
}
posted @ 2022-07-28 22:36  dgsvygd  阅读(26)  评论(0编辑  收藏  举报