题解-------CF1304E 1-Trees and Queries

传送门

题目大意

给你一棵无根树,然后询问Q次,每次把点$x$和点$y$连接,问你从点$a$到点$b$是否有一条长度为$k$的简单路径,每次询问完后会把新添加的边删除。

思路:树上LCA

题目跟2019pjt4很像,可以说这个就是那道题的树上版本。

因为每次讯问完都会把新添的边删去,所以我们只要想如何处理添完一条边后$a$到$b$的简单路径。

所以我们可以分两种情况讨论:

    1. 1.把$\left ( x,y \right )$算进$\left ( a,b \right )$的路径
    2. 2.只算$\left ( a,b \right )$的路径。

简单来说就是求a->x-〉y->b或a->y->x->b或a->b的路径, 众所周知 树上两点之间的路径长度可以用LCA来求 然后就没了。

但是怎么判断是否存在一条长度为$k$的路径呢?首先我们要知道:

如果我们向父亲节点走的话,那么就会加两条边。

不理解的可以自己画一下图。

然后我们想一下,如果$k$比路径长度大的话,我们就往父亲节点走,很容易发现,如果多出来的部分如果不是2的倍数的话,那么就不存在一条长度为$k$的路径。

代码

#include <bits/stdc++.h>

#define RI register int

using namespace std;

template <class T>
inline void read(T &x) {
    T f = 1; x = 0; char c = getchar();
    while(c > '9' || c < '0') {
        if(c == '-')
            f = -f;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    x *= f;
}

const int N = 1e5 + 7;
int n;
struct Edge {
    int nxt, to;
} edge[N << 1];
int head[N], tot;
int dep[N], st[N][21];

inline void add(int x, int y) {
    edge[++tot].nxt = head[x];
    edge[tot].to = y;
    head[x] = tot;
}

inline void Read() {
    read(n);
    for(RI i = 1; i < n; i++) {
        int x, y;
        read(x), read(y);
        add(x, y);
        add(y, x);
    }
}

inline void dfs(int x, int fa) {
    dep[x] = dep[fa] + 1;
    st[x][0] = fa;
    for(RI i = 1; i <= 20; i++)
        st[x][i] = st[st[x][i - 1]][i - 1];
    for(RI i = head[x]; i; i = edge[i].nxt) {
        int y = edge[i].to;
        if(y == fa)
            continue;
        dfs(y, x);
    }
}

inline int Lca(int x, int y) {
    if(dep[y] > dep[x])
        swap(x, y);
    for(RI i = 20; i >= 0; i--)
        if(dep[st[x][i]] >= dep[y])
            x = st[x][i];
    if(x == y)
        return x;
    for(RI i = 20; i >= 0; i--)
        if(st[x][i] != st[y][i])
            x = st[x][i], y = st[y][i];
    return st[x][0];
}

int main() {
    Read();
    dfs(1, 0);
    int T;
    read(T);
    while(T--) {
        int x, y, a, b, k;
        int res1, res2, res3;
        read(x), read(y), read(a), read(b), read(k);
        int Lca1 = Lca(a, b), Lca2_1 = Lca(a,x), Lca2_2 = Lca(y,b), Lca3_1 = Lca(a,y), Lca3_2 = Lca(x,b);
        
        res1 = dep[a] + dep[b] - 2 * dep[Lca1];
        res2 = dep[a] + dep[x] + dep[y] + dep[b] - 2 * dep[Lca2_1] - 2 * dep[Lca2_2] + 1;
        res3 = dep[a] + dep[x] + dep[y] + dep[b] - 2 * dep[Lca3_1] - 2 * dep[Lca3_2] + 1;

        if(res1 <= k && (k - res1) % 2 == 0) {
            puts("YES");
            continue;
        }
        if(res2 <= k && (k - res2) % 2 == 0) {
            puts("YES");
            continue;
        }
        if(res3 <= k && (k - res3) % 2 == 0) {
            puts("YES");
            continue;
        }
        puts("NO");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ASTiKi/p/12315573.html