• hihocoder[Offer收割]编程练习赛19 D 相交的铁路线(树上路径交)


      傻逼题... 裸的树上路径交

      两条树上的路径$[a,b]$和$[c,d]$有交,则有$lca(a,b)$在$[c,d]$上或$lca(c,d)$在$[a,b]$上。

      其实只要深度大的$lca$在另一条链上就好了,所以设$x=lca(a,b)$深度较大。

      充分性证明:$x$在$[c,d]$上,则$[a,b]$和$[c,d]$显然有交。

      必要性证明:$x$不在$[c,d]$上,如果$[a,b]$上有点$y$与$[c,d]$有交,因为$lca(c,d)$深度较小,所以$y$的深度必定小于$x$,那么$x$就不是$lca(a,b)$了,矛盾,所以如果$x$不在$[c,d]$上,$[a,b]$与$[c,d]$无交。

      证毕。

      其实根本不用证明...太容易理解了...

      判断$x$在$[c,d]$上只需要判断$x$是$lca(c,d)$的儿子且$x$是$c$或$d$的父亲。

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    using namespace std;
    const int maxn=500010;
    struct poi{int too, pre;}e[maxn<<1];
    int T, n, q, x, y, x2, y2, tot, tott;
    int top[maxn], last[maxn], dep[maxn], l[maxn], r[maxn], size[maxn], son[maxn], fa[maxn];
    inline void read(int &k)
    {
        int f=1; k=0; char c=getchar();
        while(c<'0' || c>'9') c=='-' && (f=-1), c=getchar();
        while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
        k*=f;
    }
    inline void add(int x, int y){e[++tot]=(poi){y, last[x]}; last[x]=tot;}
    void dfs1(int x)
    {
        l[x]=++tott; size[x]=1;
        for(int i=last[x], too;i;i=e[i].pre)
        if((too=e[i].too)!=fa[x])
        {
            dep[too]=dep[x]+1; fa[too]=x;
            dfs1(too); size[x]+=size[too];
            if(size[too]>size[son[x]]) son[x]=too;
        }
        
        r[x]=tott;
    }
    void dfs2(int x, int tp)
    {
        top[x]=tp;
        if(son[x]) dfs2(son[x], tp);
        for(int i=last[x], too;i;i=e[i].pre)
        if((too=e[i].too)!=fa[x] && too!=son[x]) dfs2(too, too);
    }
    inline int lca(int x, int y)
    {
        int f1=top[x], f2=top[y];
        while(f1!=f2)
        {
            if(dep[f1]<dep[f2]) swap(x, y), swap(f1, f2);
            x=fa[f1]; f1=top[x];
        }
        if(dep[x]<dep[y]) swap(x, y);
        return y;
    }
    bool check(int x, int y, int ls, int rs)
    {
        if(l[x]<l[y] || r[y]<l[x]) return 0;
        if(l[x]<=l[ls] && l[ls]<=r[x]) return 1;
        if(l[x]<=l[rs] && l[rs]<=r[x]) return 1;
        return 0;
    }
    int main()
    {
        read(T);
        while(T--)
        {
            memset(last, 0, sizeof(last)); tot=tott=0;
            read(n); read(q);
            for(int i=1;i<n;i++) read(x), read(y), add(x, y), add(y, x);
            dfs1(1); dfs2(1, 1);
            for(int i=1;i<=q;i++)
            {
                read(x); read(y); read(x2); read(y2);
                int f1=lca(x, y), f2=lca(x2, y2);
                if(dep[f1]<dep[f2]) swap(f1, f2), swap(x, x2), swap(y, y2);
                printf("%s
    ", check(f1, f2, x2, y2)?"YES":"NO");
            }
        }
    }
    View Code
  • 相关阅读:
    [转]Ubuntu设置Redhat风格的SHELL提示符PS1属性
    [转]Ubuntu Adsl 上网
    [转]Bash中的PS1详解
    Verilog 关于用task仿真应注意的一个问题
    [转]提高编程技能最有效的方法
    [转]ubuntu 终端常用命令
    [转]VMware Workstation 7.1 正式版 For Linux
    [转]Vim基本操作
    [转]Ubuntu Linux下设置IP的配置命令
    xilinxftp.newlocation
  • 原文地址:https://www.cnblogs.com/Sakits/p/8085864.html
Copyright © 2020-2023  润新知