Codeforces Round #620 E 1-Trees and Queries LCA

題目鏈接:https://codeforces.com/contest/1304/problem/E

題意:給你一顆樹,多次詢問,每次給你一條連邊x,y的機會,問你a到b是否存在k條邊的路
其中某些邊可以重複任意次
思路;不加邊時只要k>= dis(a, b) 並且奇偶性相同就行,因爲邊可以重複走,考慮加邊時
帶來的影響是多了dis(a, x) + dis(y, b) + 1, dis(a, y) + dis(x, b) + 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 po pop_back
#define pb push_back
#define mk make_pair
#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;
const ll linf = 0x3f3f3f3f3f3f3f3f;
//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]; //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 calc(int x, int y)
{
    return d[x] + d[y] - 2 * d[LCA(x, y)];
}
bool check(int k, int d)
{
    if(k >= d && k % 2 == d % 2) return 1;
    return 0;
}

int main()
{
    scanf("%d", &n);
    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是根節點
    scanf("%d", &m);
    while(m--)
    {
        int x, y, a, b, k;
        scanf("%d%d%d%d%d", &x, &y, &a, &b, &k);
        if(check(k, calc(a, b)) || check(k, calc(a, x) + calc(y, b) + 1) || check(k, calc(a, y) + calc(x, b) + 1))
            printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}


 

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