[Codeforces1304E]1-Trees and Queries

哇比赛的时候查不出来wtcl。。

还有,我不相信是 E 题

题意 Description

给定一个 \(n\) 个点的树,相邻点的距离为 \(1\)

\(q\) 个询问,每个询问包含5个整数: \(x,y,a,b,k\)

含义是:在原树上新连上一条边 \((x,y)\) ,要求判断一下从 \(a\) 点是否有距离为 \(k\) 的到 \(b\) 的路径。

注意:

  • 每个询问是独立的,即上次询问加上的边,不能为这一次的询问所用。

  • 这一条路径也许会重复经过某一条边或某一点。

题解 Solution

涉及树上距离,考虑 LCA 。

对于每个询问,我们先判断一下 \(a,b\) 间有没有长度为 \(k\) 的路径,再判断一下经过边 \(x,y\) 的路径有没有长度为 \(k\) 的即可。

对于第一个:

下面的 \(\operatorname{dist}(u,v)\) 表示 \(u,v\) 的最短距离。

  • 快速求得 \(\operatorname{dist}(u,v)\) 可以通过 LCA 来求,公式: \(\operatorname{dist}(u,v)=depth_u+depth_v-2\times depth_{\operatorname{LCA}(u,v)}\) 。其中 \(\operatorname{LCA}(u,v)\) 表示结点 \(u,v\)最近公共祖先

  • 先求出 \(a,b\) 的最短距离 \(D = \operatorname{dist}(a,b)\)。假如说 \(D\)\(k\) 的奇偶性一致且 \(k\ge D\) 的话,那么就是 YES 。为什么是奇偶性?因为如果把这条最短的路径“折一下”(1->2->3->4 折成 1->2->3->2->3->4),总长度会加二,奇偶性不变。倘若 \(k\ge D\) ,那么这样一直折下去,路径长度一定可以到达 \(k\)

  • 对于新加入的边,我们计算出 \(D'=\min (\operatorname{dist}(a,x)+\operatorname{dist}(b,y)+1,\operatorname{dist}(a,y)+\operatorname{dist}(b,x)+1)\),即 \(a\)\(b\) 经过边 \((x,y)\) 的最短路径的长度。如果 \(D'\)\(k\) 的奇偶性一致且 \(k \ge D'\) 的话就是可行的。

  • 注意, \(D\)\(D'\) 必须 \(\le k\) 否则是不成立的。因为“折”是不可以“折”负数次的。

代码 Source Code

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;

int get_int()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
        x=x*10+c-'0',c=getchar();
    return f*x;
}

const int N=1e5+5;
vector<int> G[N];
int depth[N],father[N];
int maxson[N],size[N],top[N]/*link tops*/;
int n,s,m;

void DFS1(const int &now,const int &from)
{
    father[now]=from,depth[now]=depth[from]+1,size[now]=1;
    for(register int i=0;i<G[now].size();i++)
    {
        int next=G[now][i];
        if(next==father[now])continue;
        DFS1(next,now);
        size[now]+=size[next];
        if(size[maxson[now]]<size[next]||maxson[now]==0)
            maxson[now]=next;
    }
}

void DFS2(const int &now,const int &lktp)//link top
{
    top[now]=lktp;
    if(size[now]>1)DFS2(maxson[now],lktp);
    for(register int i=0;i<G[now].size();i++)
    {
        int next=G[now][i];
        if(next==father[now])continue;
        if(next==maxson[now])continue;
        DFS2(next,next);
    }
}

inline void Prepare_Data(const int &s)
{
    memset(maxson,0,sizeof(maxson));
    depth[0]=0,father[s]=0;
    DFS1(s,0),DFS2(s,s);
}

inline int Query_LCA(int u,int v)
{
    for(;top[u]!=top[v];)
        (depth[top[u]]>=depth[top[v]])?u=father[top[u]]:v=father[top[v]];
    return depth[u]<depth[v]?u:v;
}

inline int Get_Dist(int u,int v)
{
    int lca=Query_LCA(u,v);
    return depth[v]+depth[u]-2*depth[lca];
}

signed main()
{
    n=get_int(),s=1;
    for(register int i=1;i<n;i++)
    {
        int u=get_int(),v=get_int();
        G[u].push_back(v);
        G[v].push_back(u);
    }
    Prepare_Data(s);
    m=get_int();
    while(m--)
    {
        int x=get_int(),y=get_int(),a=get_int(),b=get_int(),k=get_int();
        int dis=Get_Dist(a,b);
        if(dis<=k&&dis%2==k%2) {puts("YES");continue;}
        dis=min(Get_Dist(a,x)+Get_Dist(b,y)+1,Get_Dist(a,y)+Get_Dist(b,x)+1);
        if(dis<=k&&dis%2==k%2) puts("YES");
        else puts("NO");
    }
    return 0;
}
  • P.S. LCA部分是用树链剖分写的,倍增或 RMQ 也可以。

算法复杂度 \(\Theta (n+q\log n)\)

猜你喜欢

转载自www.cnblogs.com/-Wallace-/p/12337837.html