Codeforces Round #620 (Div. 2) ——E

Codeforces Round #620 (Div. 2) ——E

题意:

给x,y加一条边,问是否存在k条路径,可以来回走。

题解:

这道题显然是树上的问题,首先我们先求出两点的最短路径,如果k小于我们的最短路径显然是不行。然后我们分类讨论的时候判断奇偶就行了。因为我们每条边来回走肯定是走偶数次的,所以不改变我们的奇偶,所以我们最后判断我们最短路的奇偶性和k是否一样就行了。

#include 
using namespace std;
const int N=3e6+5;
int depth[N],fa[N][20];
int ne[N],cnt,head[N],e[N];
void add(int a,int b)
{
    ne[cnt]=head[a],e[cnt]=b,head[a]=cnt++;
}
void build(int u)
{
    queue<int> q;
    depth[u]=1;
    q.push(1);
    while(!q.empty()) {
        int t=q.front(); q.pop();
        for (int i = head[t]; ~i; i = ne[i]) {
            int j = e[i];
            if(depth[j]==-1) {
                depth[j] = depth[t] + 1;
                q.push(j);
                fa[j][0] = t;
                for (int k = 1; k <= 19; k++) {
                    int arc = fa[j][k - 1];
                    fa[j][k] = fa[arc][k - 1];
                }
            }
        }
    }
}
int lca(int x,int y)
{
    if(depth[x]<depth[y]) swap(x,y);
    for(int i=19;i>=0;i--){
        if(depth[fa[x][i]]>=depth[y]){
            x=fa[x][i];
        }
    }
    if(x==y) return x;
    for(int i=19;i>=0;i--){
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[x][0];
}
int dis(int u,int v)
{
    int d=lca(u,v);
    return depth[u]+depth[v]-2*depth[d];
}
int main()
{
    memset(head,-1,sizeof head);
    memset(depth,-1,sizeof depth);
    int n; scanf("%d",&n);
    for(int i=1;i<n;++i){
        int a,b; scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    depth[0]=0;
    build(1);
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,a,b,k;
        scanf("%d%d%d%d%d",&x,&y,&a,&b,&k);
        int d1=dis(a,b),d2=dis(a,x)+dis(b,y)+1,d3=dis(a,y)+dis(b,x)+1;
        if(k>=d1&&(k-d1)%2==0)puts("YES");
        else if(k>=d2&&(k-d2)%2==0)puts("YES");
        else if(k>=d3&&(k-d3)%2==0)puts("YES");
        else puts("NO");
    }
}

你可能感兴趣的:(图论)