zoukankan      html  css  js  c++  java
  • 【bzoj1787】[Ahoi2008]Meet 紧急集合

    Description

    Input

    Output

    Sample Input

    6 4
    1 2
    2 3
    2 4
    4 5
    5 6
    4 5 6
    6 3 1
    2 4 4
    6 6 6

    Sample Input

    5 2
    2 5
    4 1
    6 0

    HINT

    【解析】

    三个点两两的lca一共有3个,其中两个一样的,那个不一样的就是集合点。

    为什么是那个点呢???求助~

    然后求三个点到集合点的距离。

    今晚徐老大给我讲为什么那个点最优了,自己整理一下加深理解。

    首先需要集合的三个点是x1,x2,x3,两两的lca为lca1,lca2,其中有两对重着,所以三个点两两求lca有两个。

    我们可以得出几个结论:

    (1)树上三个点两两求lca,所求的三个lca中两个是相同的。

    (2)需要集合的点到他们三个lca中不同的那个lca集合最优。

    首先我们先证明一下 三个点到他们lca集合路径会最优(你先别管是哪个lca,反正是lca就对了)。

    对于上图我们发现,走红色路径一定比不是红色路径的路径优。

    ①假设我们到结点编号为1的点集合,当集合点(也就是目前的编号为1的那个点)向靠近他们lca的方向移动时,(假设移向他爸爸,正好是lca1),那么跟之前的路径相比,

    x2,x3比之前的路径长度各-1,x1比之前的路径长+1,两个点路径长-1,一个点路径长+1,显然与之前相比,向lca的方向移动,结果更优。

    ②假设集合点在结点4时,我们往靠近lca的方向移动,假设到结点3,发现x1,x2,x3的路径与原来相比-1,显然更能说明集合点往lca方向移动更优。

    ③假设x3在结点6,(这种情况是x1,x2,x3都在lca的子树中,说明三个点的两两lca相同),假设此时集合点为结点1,我们向靠近lca的方向移动,到lca1,此时

    x2,x3的路径长-1,(注意此时x3已经在结点6了),x1的路径长+1,显然比集合点改变之前更优。

    综上所述我们发现集合点在他们的lca路径最优。

    反正三个点两两lca只有3个我们枚举一下在哪个lca时路径最优即可。

    对于结论(2),两个相同的lca一定在不同的那个lca上面,也就是两个相同的lca比不同的那个lca深度浅。

    为什么呢?因为一个点到它lca的路径是唯一的。(仍是原图中标号的x1,x2,x3),lca1是x1,x2的lca,lca2是x2,x3的lca。

    如果从x1向上冲,一定要先冲破他自己的lca1在冲向lca2,又因为lca1的深度深,相对于lca2少跑一层,所以在lca1最优,或者是

    自己像刚才证明那样证明一下。

    【代码】

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define N 500003
    int sumedge,n,m,x,y,A,B,C,D,a,b,c,d,L;
    int head[N],size[N],deep[N],dis[N],dad[N],top[N];
    struct Edge
    {
        int x,y,next;
        Edge(int x=0,int y=0,int next=0):x(x),y(y),next(next){}
    }edge[N<<1];
    inline int read()//读入优化 
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add_edge(int x,int y)//加边 
    {
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    inline void dfs(int x)//树剖求lca 
    {
        size[x]=1;
        deep[x]=deep[dad[x]]+1;
        for(int i=head[x];i;i=edge[i].next)
        {
            if(dad[x]!=edge[i].y)
            {
                dad[edge[i].y]=x;
                dis[edge[i].y]=dis[x]+1;
                dfs(edge[i].y);
                size[x]+=size[edge[i].y];
            }
        }
    }
    inline void dfs1(int x)//树剖求lca 
    {
        int s=0;
        if(!top[x])top[x]=x;
        for(int i=head[x];i;i=edge[i].next)
        {
            if(dad[x]!=edge[i].y&&size[edge[i].y]>size[s])
            {
                s=edge[i].y;
            }
        }
        if(s)
        {
            top[s]=top[x];
            dfs1(s);
        }
        for(int i=head[x];i;i=edge[i].next)
        {
            if(dad[x]!=edge[i].y&&edge[i].y!=s)
            dfs1(edge[i].y);
        }
    }
    inline int lca(int x,int y)//树剖求Lca 
    {
        for(;top[x]!=top[y];)
        {
            if(deep[top[x]]>deep[top[y]])
            swap(x,y);
            y=dad[top[y]];
        }
        if(deep[x]>deep[y])
        swap(x,y);
        return x;
    }
    inline int l(int x,int y)//树上两点之间的最短路径 两个点到跟的路径长度减去两倍的lca到根的长度。  
    {
        return dis[x]+dis[y]-2*dis[lca(x,y)];
    }
    int main()
    {
        n=read();m=read();//n个点 m个询问
        for(int i=1;i<n;i++)
        {
            x=read();y=read();
            add_edge(x,y);//加边 
            add_edge(y,x);
        }
        dfs(1);//树剖求lca的dfs 
        dfs1(1);
        for(int i=1;i<=m;i++)
        {
            a=read();b=read();c=read();
            A=lca(a,b);B=lca(a,c);C=lca(b,c);
            D=A^B^C;//三个lca中有两个相同的 D是那个不同的 
            L=l(a,D)+l(b,D)+l(c,D);//三点到D的距离 用树上两点之间的最短路径做。 
            printf("%d %d
    ",D,L);
        }
        return 0;
    }

     //不知道为什么同学用的树剖和vector数组存边一直re。。。。然后写上读入优化就过了???还好我用的邻接表~

  • 相关阅读:
    AndroidUI的组成部分ProgressBar
    NVIDIA+关联2015写学校招收评论(嵌入式方向,上海)
    谈论json
    排序算法(三):插入排序
    逻辑地址、线性地址、物理地址以及虚拟存储器
    逻辑地址、线性地址和物理地址的关系
    堆和栈都是虚拟地址空间上的概念
    缺页异常详解
    虚拟内存-插入中间层思想
    深入理解计算机系统之虚拟存储器
  • 原文地址:https://www.cnblogs.com/zzyh/p/6817339.html
Copyright © 2011-2022 走看看