CF-div2-620-E. 1-Trees and Queries LCA 树上点距离

Posted fisherss

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF-div2-620-E. 1-Trees and Queries LCA 树上点距离相关的知识,希望对你有一定的参考价值。

思路

树链剖分求出LCA
用LCA求两点之间距离(借助到根的距离):depth[x] + depth[y] - 2*depth[LCA];
加边后a,b两点可以保持距离为k的条件: k>=改变后的距离; 改变后的距离刚好等于k,如果不等那么距离相差偶数,来回走来走去就能走到走凑成k

考虑加边对a,b距离的影响;有三种情况
1.加边后,不影响a,b
2.a先到x,x再走到y(这里新加的边,距离为1),y再走到b
3.a先到y,y再走到x(+1),x再走到b

判断最终距离<=k,并且相差为偶数

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+100;
vector<int> g[maxn];
ll fa[maxn],depth[maxn],sz[maxn],son[maxn],id[maxn],rk[maxn],top[maxn],bot[maxn];
int cnt = 0;
int n,q,root = 1;

/*
树链剖分求LCA
LCA求两点之间距离(借助到根的距离):depth[x] + depth[y] - 2*depth[LCA];
可以保持距离为k的条件: k>=改变后的距离; 改变后的距离刚好等于k,如果不等那么距离相差偶数,来回走来走去就能走到走凑成k
*/

void dfs(int x,int deep){
    depth[x] = deep;
    sz[x] = 1;
    for(int li = 0;li<g[x].size();li++){
        int i = g[x][li];
        if(i == fa[x]) continue;
        fa[i] = x;
        dfs(i,deep+1);
        sz[x] += sz[i];
        if(sz[i] > sz[son[x]]) son[x] = i;
    }
}

void dfs2(int x,int tp){
    top[x] = tp;
    id[x] = ++cnt;
    rk[cnt] = x;
    if(son[x]) dfs2(son[x],tp),bot[x] = bot[son[x]];
    else bot[x] = x;
    for(int li=0;li<g[x].size();li++){
        int i = g[x][li];
        if(i != fa[x] && i != son[x])
            dfs2(i,i);
    }
}

int lca(int u,int v){
    while(top[u] != top[v]){
        if(depth[top[u]] < depth[top[v]]) swap(u,v);
        u = fa[top[u]];
    }
    if(depth[u] < depth[v]) return u;
    return v;
}

//求两点之间的简单路径距离 
ll dis(int x,int y){
    int LCA = lca(x,y);
    return depth[x] + depth[y] - 2*depth[LCA];
}

int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n-1;i++){
        ll u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(root,1);
    dfs2(root,root);
    cin>>q;
    while(q--){
        ll x,y,a,b,k;
        cin>>x>>y>>a>>b>>k;
        ll ans = 0x3f3f3f3f;
        //a,b两点与x,y有三种关系
        ll dist1 = dis(a,b); //无关 
        ll dist2 = dis(a,x) + dis(y,b) + 1; //a先到x,x再走到y(这里新加的边,距离为1),y再走到b 
        ll dist3 = dis(a,y) + dis(x,b) + 1;
        bool flag = false;
        if((k - dist1)%2 == 0 && dist1 < ans) ans = dist1;
        if((k - dist2)%2 == 0 && dist2 < ans) ans = dist2;
        if((k - dist3)%2 == 0 && dist3 < ans) ans = dist3;
        if(ans <= k) flag = true;
        if(flag) puts("YES");
        else puts("NO");
    }
    return 0;
}
/*
5
1 2
2 3
3 4
4 5
5
1 3 1 2 2
1 4 1 3 2
1 4 1 3 3
4 2 3 3 9
5 2 3 3 9
*/

以上是关于CF-div2-620-E. 1-Trees and Queries LCA 树上点距离的主要内容,如果未能解决你的问题,请参考以下文章

CF-div3-635-E - Three Blocks Palindrome| 二分

CF-Div2-832 D. Yet Another Problem(bitmask&结论)

CF-Div2-832 D. Yet Another Problem(bitmask&结论)

CF-div3-611-F. DIY Garland 优先队列 构造树

CF-div2-620-D. Shortest and Longest LIS 贪心,双指针

1-Trees and Queries