Codeforces Round #629 (Div. 3) E. Tree Queries LCA

題目鏈接:https://codeforces.com/contest/1328/problem/E
題意:給你一棵樹,多次詢問每次給你一個集合,問你能否選一條鏈使得集合所有點到這條鏈的距離不大於1
思路:每次將集合按照深度排序,然後我們用深度最大的點和其餘點依次求LCA,然後判斷深度差是否大於1
如果大於就說明不滿足。 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fi first
#define se second
#define ls rt << 1
#define rs rt << 1|1
#define lson l, mid, ls
#define rson mid + 1, r, rs
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ull unsigned long long
#define pdd pair<double, double>
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
//head[u] 和 tot的初始值都爲-1
int head[maxn << 1], nxt[maxn << 1], to[maxn << 1], ver[maxn << 1];
int f[maxn][22], d[maxn], dis[maxn], a[maxn]; //d[x]表示x的深度, dis[y]表示y到根的距離
int n, m, s, lg, tot = -1;
queue<int> q;
void add(int u, int v, int w)
{
	nxt[++tot] = head[u]; //當前邊的後繼
	head[u] = tot; //起點u的第一條邊
	to[tot] = v; //當前邊的終點
	ver[tot] = w; //當前邊的權值
}
void bfs(int s)
{
    while(!q.empty()) q.pop();
    q.push(s), d[s] = 1;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = head[u]; ~i; i = nxt[i])
        {
            int v = to[i];
            if(d[v]) continue;
            d[v] = d[u] + 1;
            dis[v] = dis[u] + ver[i];
            f[v][0] = u;
            for(int j = 1; j <= lg; ++j)
                f[v][j] = f[f[v][j - 1]][j - 1];
            q.push(v);
        }
    }
}
int LCA(int u, int v)
{
    if(d[u] > d[v]) swap(u, v);
    for(int i = lg; i >= 0; --i) //u是v的祖先的情況
    {
        if(d[f[v][i]] >= d[u]) //不在同一條鏈上就處理到深度相同
            v = f[v][i];
    }
    if(u == v) return u;
    for(int i = lg; i >= 0; --i) //深度相同就可以同時倍增求
    {
        if(f[u][i] != f[v][i])
            u = f[u][i], v = f[v][i];
    }
    return f[u][0];
}

int main()
{
    scanf("%d%d", &n, &m);
    lg = (int)(log(n) / log(2)) + 1; //枚舉的深度
    for(int i = 0; i <= n; ++i) head[i] = -1, d[i] = 0;
    tot = -1;
    for(int i = 1; i < n; ++i)
    {
        int u, v, w = 1;
        scanf("%d%d", &u, &v);
        add(u, v, w), add(v, u, w);
    }
    bfs(1); //s是根節點
    while(m--)
    {
        int k, Max = 0, id;
        scanf("%d", &k);
        for(int i = 1; i <= k; ++i)
        {
            scanf("%d", &a[i]);
            if(Max < d[a[i]])
                Max = d[a[i]], id = a[i];
        }
        int flag = 1;
        for(int i = 1; i <= k; ++i)
        {
            int fa = LCA(id, a[i]);
            if(abs(d[fa] - d[a[i]]) > 1)
            {
                flag = 0;
                break;
            }
        }
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章