CF1304E 1Trees and Queries(LCA倍增算法)

题意:

给你一棵树。

每次询问,在x和y顶点之间添加了一条边后,如果存在一条路径,该路径恰好包含从a到b的k条边,可以保证原始树不存在x和y之间的边,路径可以经过相同的顶点和边。每个查询相互独立。

题解:

可以推出有三种可能的路径。

a->b

a->x->y->b

a->y->x->b

求出这三种路径的距离,有一条和k的奇偶性相同,就输出YES。

求路径需要套一个LCA倍增算法的模板。

模板一:

用于单颗树,写起来比较简单

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+14;
int N,Q;
int father[18][maxn];
int h[maxn];
vector<int> g[maxn];
void dfs (int x) {
    for (int i=0;i<g[x].size();i++) {
        int v=g[x][i];
        if (v==father[0][x]) continue;
        father[0][v]=x;
        h[v]=h[x]+1;
        dfs(v); 
    }
} 
int lca (int x,int y) {
    if (h[x]<h[y]) swap(x,y);
    for (int i=17;i>=0;i--) 
        if (h[x]-h[y]>>i) x=father[i][x];
    if (x==y) return x;
    for (int i=17;i>=0;i--) {
        if (father[i][x]!=father[i][y]) {
            x=father[i][x];
            y=father[i][y];
        }
    }
    return father[0][x];
} 
int getDis (int x,int y) {
    return h[x]+h[y]-h[lca(x,y)]*2;
} 
bool check (int x,int y) {
    return y>=x&&x%2==y%2;
}
int main () {
    scanf("%d",&N);
    for (int i=1;i<N;i++) {
        int a,b;
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(1);
    for (int i=1;i<=17;i++) {
        for (int j=1;j<=N;j++) 
            father[i][j]=father[i-1][father[i-1][j]];
    }
    scanf("%d",&Q);
    for (int i=0;i<Q;i++) {
        int x,y,a,b,k;
        scanf("%d%d%d%d%d",&x,&y,&a,&b,&k);
        if (check(getDis(a,b),k)||
            check(getDis(a,x)+getDis(y,b)+1,k)||
            check(getDis(a,y)+getDis(x,b)+1,k))
            printf("YES\n");
        else printf ("NO\n");
    }
    return 0;
}

模板二:

用于森林

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+14;
int N,Q;
int father[30][maxn];
int h[maxn];
vector<int> g[maxn];
void dfs (int x,int u) {
    h[x]=h[u]+1;
    father[0][x]=u;
    for (int i=1;(1<<i)<=h[x];i++) 
        father[i][x]=father[i-1][father[i-1][x]];
    for (int i=0;i<g[x].size();i++) {
        int v=g[x][i];
        if (v==father[0][x]) continue;
        dfs(v,x);
    }
}
int lca (int x,int y) {
    if (h[x]>h[y]) swap(x,y);
    for (int i=20;i>=0;i--) 
        if (h[x]<=h[y]-(1<<i)) y=father[i][y];
    if (x==y) return x;
    for (int i=20;i>=0;i--) {
        if (father[i][x]!=father[i][y]) {
            x=father[i][x];
            y=father[i][y];
        }
    }
    return father[0][x];
}
int getDis (int x,int y) {
    return h[x]+h[y]-h[lca(x,y)]*2;
} 
bool check (int x,int y) {
    return y>=x&&x%2==y%2;
}
int main () {
    scanf("%d",&N);
    for (int i=1;i<N;i++) {
        int a,b;
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(1,1);
    scanf("%d",&Q);
    for (int i=0;i<Q;i++) {
        int x,y,a,b,k;
        scanf("%d%d%d%d%d",&x,&y,&a,&b,&k);
        if (check(getDis(a,b),k)||
            check(getDis(a,x)+getDis(y,b)+1,k)||
            check(getDis(a,y)+getDis(x,b)+1,k))
            printf("YES\n");
        else printf ("NO\n");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zhanglichen/p/12425536.html