【LCA】BZOJ1832 & BZOJ1787(AHOI)-集会

【题目大意】

一个图有n个点n-1条边(也就是说是一棵树),求其中三点共同到达某一点经过总共的最少边数以及共同到达的那一点。

【思路】

借用一下黄学长给的结论:三个点两两取LCA,其中必有两个相同,则另外一个点就是答案。

注意BZOJ大数据要用scanf和printf,因为cout的原因RE了好几次_(:зゝ∠)_基本算是一道标程类的题目了啦。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<vector>
  8 const int MAXN=500001;
  9 const int M=20;
 10 using namespace std;
 11 int n,m;
 12 vector<int> G[MAXN];
 13 int fa[MAXN][M];
 14 int dep[MAXN];
 15 
 16 void dfs(int v,int p,int d)
 17 {
 18     fa[v][0]=p;
 19     dep[v]=d;
 20     for (int i=0;i<G[v].size();i++)
 21         if (G[v][i]!=p) dfs(G[v][i],v,d+1);
 22 }
 23 
 24 void kb()
 25 {
 26     for (int i=1;i<M;i++)
 27         for (int j=1;j<=n;j++)
 28         {
 29             fa[j][i]=fa[fa[j][i-1]][i-1];
 30         }
 31 }
 32 
 33 void init()
 34 {
 35     scanf("%d%d",&n,&m);
 36     for (int i=0;i<n-1;i++)
 37     {
 38         int fr,to;
 39         scanf("%d%d",&fr,&to);
 40         G[fr].push_back(to);
 41         G[to].push_back(fr);
 42     }
 43     dfs(1,0,0);
 44     kb();
 45 }
 46 
 47 int swim(int x,int H)
 48 {
 49     for (int i=0;H>0;i++)
 50     {
 51         if (H&1) x=fa[x][i];
 52         H/=2;
 53     }
 54     return x;
 55 }
 56 
 57 int LCA(int u,int v)
 58 {
 59     if (dep[u]<dep[v]) swap(u,v);
 60     u=swim(u,dep[u]-dep[v]);
 61     if (u==v) return u;
 62     for (int i=M-1;i>=0;i--)
 63     {
 64         if (fa[u][i]!=fa[v][i])
 65         {
 66             u=fa[u][i];
 67             v=fa[v][i];
 68         }
 69     }
 70     return fa[u][0];
 71 }
 72 
 73 int dis(int x,int y)
 74 {
 75     int z=LCA(x,y);
 76     int re=dep[x]+dep[y]-2*dep[z];
 77     return re;
 78 }
 79 
 80 void query()
 81 {
 82     int u,v,w;
 83     for (int i=0;i<m;i++)
 84     {
 85         scanf("%d%d%d",&u,&v,&w);
 86         int uv=LCA(u,v);
 87         int uw=LCA(u,w);
 88         int vw=LCA(v,w);
 89         int pos;
 90         if (uv==uw) pos=vw;
 91             else if (uv==vw) pos=uw;
 92                 else pos=uv;
 93          int cost=dis(u,pos)+dis(v,pos)+dis(w,pos);
 94          printf("%d %d\n",pos,cost);
 95     }
 96 }
 97 
 98 int main()
 99 {
100     init();
101     query();
102     return 0;
103 }

 

转载于:https://www.cnblogs.com/iiyiyi/p/5138009.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值