题解CF1304E【1木とクエリ】

序文

ゲーム、最終的に\(5 \)分、私はこの問題を考える(アイデアは\)\、しかし、ゲームが終わって、終了しませんでした。

テキスト

タイトルの意味

この質問オブジェクト手段は、各ツリーに\(X \)\(Y \)ノード接続\(1 \)エッジ、Q \(A \)\(B \)の間いかなる長さが存在しない\(K \)側。

分析

最初は、私はこの質問を考えて、ここで、リングのツリーに出て行くのを見た、実際には、問題を解決する方法があり、機械加工部品この質問の著者は章を書いたという疑問もありますが、似ています問題の解決策ではなく、学生が見て行くことができます。

この質問はトリッキーなところがあり、プラスである\(1 \)この場所の側面に対処することは困難ですが、私たちは実際には、それについて考えることができ、合計の可能なパス3

  1. \(\ \ Bを意味する)。これは、ほとんど元のパスです。

  2. \(\ \ X意味意味 yは\ \ Bを意味する) 。これは、によって達成される\(X、Y \)パス

  3. \(\ \ Yを意味意味し 、xは\ \ Bを意味する) 。これは、によって達成される\(Y、X \)パス。

即ち

bool check(int x,int y){
    if(x<=y&&x%2==y%2)return true;
    return false;
}
while(T--){
    int x,y,a,b,k;
    read(x);read(y);read(a);read(b);read(k);
    int ab=dist(a,b),ax=dist(a,x),yb=dist(b,y),ay=dist(a,y),bx=dist(b,x);
    if(check(ab,k)||check(ax+yb+1,k)||check(ay+bx+1,k))puts("YES");
    else puts("NO");
}

処理行くバック

読者が行く、求めることができる\(1 \)ポイント、バック歩いて、我々はこれをどのようにしたらよいでしょうか?我々は見つけるために行ってきました\(1 \)戻ってきてポイントをため、(1 \)\回パスの長さがある(2 \)\我々のように\(3 \)限り、パス\(1 \)でパス大会\(2 \)条件、それはそのような長さの存在を示し\(K \)パス。

  1. パスの長さ\(\当量K \)明らかに、この1。長さは\(> K \) 明らかに違法です。

  2. パスの長さと\(K \)同じパリティ。このアプローチは、戻る、同じパリティ、ベースの長さは、から構成されてもよいように、偶数の2つの数の間の差を表す\(K \)パス。

前処理\(2 \)点間の距離

私たちはただ、2点間の距離は、要件の外に明らかにされ、私たちは前処理を必要と述べた(LCA \)\、学生は左折することができない問題領域へのソリューションを、私は最も単純な乗算を使用、\(LCAを\ )

void dfs(int x,int f){
    dep[x]=dep[f]+1;
    fa[x][0]=f;
    for(int i=1;(1<<i)<=dep[x];i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=head[x];i;i=nxt[i])
        if(t[i]!=f)dfs(t[i],x);
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    while(dep[x]>dep[y])x=fa[x][lg[dep[x]-dep[y]]-1];
    if(x==y)return x;
    for(int k=lg[dep[x]]-1;k>=0;k--)
        if(fa[x][k]!=fa[y][k])x=fa[x][k],y=fa[y][k];
    return fa[x][0];
}
int dist(int x,int y){//x号节点和y号节点的距离
    int z=lca(x,y);
    return dep[x]+dep[y]-dep[z]*2;
}

コード

#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &FF){
    T RR=1;FF=0;char CH=getchar();
    for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
    for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
    FF*=RR;
}//快读
template<typename T>void write(T x){
    if(x<0)putchar('-'),x*=-1;
    if(x>9)write(x/10);
    putchar(x%10+48);
}//快写
int dep[500010],fa[500010][22],lg[500010],head[500010],nxt[500010],t[500010],tot;
void add(int x,int y){
    t[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}//连边
void dfs(int x,int f){
    dep[x]=dep[f]+1;
    fa[x][0]=f;
    for(int i=1;(1<<i)<=dep[x];i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=head[x];i;i=nxt[i])
        if(t[i]!=f)dfs(t[i],x);
}//预处理father
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    while(dep[x]>dep[y])x=fa[x][lg[dep[x]-dep[y]]-1];
    if(x==y)return x;
    for(int k=lg[dep[x]]-1;k>=0;k--)
        if(fa[x][k]!=fa[y][k])x=fa[x][k],y=fa[y][k];
    return fa[x][0];
}//LCA
int dist(int x,int y){
    int z=lca(x,y);
    return dep[x]+dep[y]-dep[z]*2;
}//x、y两点之间的距离
bool check(int x,int k){
    if(x<=k&&x%2==k%2)return true;
    return false;
}//检查长度为x的边是否满足前文讲得2个条件
int main(){
    int n;
    read(n);
    for(int i=1;i<n;i++){
        int x,y;
        read(x);read(y);
        add(x,y);add(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++)lg[i]=lg[i-1]+(1<<lg[i-1]==i);//预处理除log
    int T;
    read(T);
    while(T--){
        int x,y,a,b,k;
        read(x);read(y);read(a);read(b);read(k);
        int ab=dist(a,b),ax=dist(a,x),yb=dist(b,y),ay=dist(a,y),bx=dist(b,x);//3条边
        if(check(ab,k)||check(ax+yb+1,k)||check(ay+bx+1,k))puts("YES");//有1条符合条件,就代表有
        else puts("NO");//3条都不符合就代表没有
    }
    return 0;
}

追伸

この質問はまだについて非常に価値が思考するだけでなく、蓄積された経験ある木のプラスを参照するには、\(1 \)エッジは、必ずしもリングツリーに行きたいです優秀な学生は、賞賛を指して質問を持つことができることを願っていますが、コメント領域にそれを表現してください、私の説明は再びそれを完了するのに十分なされています。

おすすめ

転載: www.cnblogs.com/zhaohaikun/p/12323505.html