• [ AHOI 2008 ] Meet


    (\)

    (Description)


    一棵(N)个节点的树,每条边权都为(1)
    (M)组询问,每次给出三个点(A_i,B_i,C_i),求从三个点分别出发,移动到同一个点的路径最小权值和。

    • (N,Min [1,5 imes10^5])

    (\)

    (Solution)


    • 如果是两个点,显然在两点到(Lca)的路径上任意位置会合都是花费最小的方案。扩展到三个点,我们猜测最优答案也是产生在两点(Lca)或一段路径上。手玩一会样例或者自己造一点数据,可以发现一个事实:三点两两求(Lca),必然至少有两个(Lca)是同一个点,形象化的表示:

      图中所示的是最一般的情况,可以发现两个相同的(Lca)的深度一定不会大于单独的(Lca)的深度,因为相同的(Lca)产生于,单独的(Lca)与不产生这个单独的(Lca)的点求(Lca)

    • 此时方案就显然了,图中所有单色的边是一定要被走一次的,如果在图中的(L2)处会和,双色的边会被(b,c)各走一次,而若在单独的(Lca)处会和,双色的边只会走一次,所以我们直接判断出单独的(Lca),让第三个点((a))去往那里集合就好,路径长度可以在找(Lca)的时候顺便求出。

    (\)

    (Code)


    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 500010
    #define R register
    #define gc getchar
    using namespace std;
    
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
    
    int n,m,t,tot,d[N],hd[N],f[N][20];
    struct edge{int to,nxt;}e[N<<1];
    
    inline void add(int u,int v){
      e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
    }
    
    queue<int> q;
    inline void bfs(){
      q.push(1); d[1]=1;
      while(!q.empty()){
        int u=q.front(); q.pop();
        for(R int i=hd[u],v;i;i=e[i].nxt)
          if(!d[v=e[i].to]){
            d[v]=d[u]+1; f[v][0]=u;
            for(R int i=1;i<=t;++i) f[v][i]=f[f[v][i-1]][i-1];
            q.push(v);
          }
      }
    }
    
    inline pair<int,int> lca(int u,int v){
      int res=0;
      if(d[u]>d[v]) u^=v^=u^=v;
      for(R int i=t;~i;--i) if(d[f[v][i]]>=d[u]) v=f[v][i],res+=(1<<i);
      if(u==v) return make_pair(u,res);
      for(R int i=t;~i;--i)
        if(f[u][i]!=f[v][i]) v=f[v][i],u=f[u][i],res+=(1<<(i+1));
      return make_pair(f[u][0],res+2);
    }
    
    int main(){
      t=log2(n=rd())+1; m=rd();
      for(R int i=1,u,v;i<n;++i){
        u=rd(); v=rd(); add(u,v); add(v,u);
      }
      bfs();
      pair<int,int> l1,l2,l3;
      for(R int i=1,a,b,c;i<=m;++i){
        a=rd(); b=rd(); c=rd();
        l1=lca(a,b); l2=lca(a,c); l3=lca(b,c);
        if(l1.first==l2.first) printf("%d %d
    ",l3.first,l3.second+lca(l3.first,a).second);
        else if(l1.first==l3.first) printf("%d %d
    ",l2.first,l2.second+lca(l2.first,b).second);
        else if(l2.first==l3.first) printf("%d %d
    ",l1.first,l1.second+lca(l1.first,c).second);
      }
      return 0;
    }
    
  • 相关阅读:
    什么叫大数据,与云计算有何关系
    未来机器时代 马云担心的居然是男性找不到工作
    浏览器原生登陆验证实现
    eclipse-java-style.xml
    tomcat和应用集成
    简单springboot及springboot cloud环境搭建
    maven module
    maven scope
    java ReentrantLock Condition
    抓取动态网页
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9682332.html
Copyright © 2020-2023  润新知