[AHOI2008]紧急集合 / 聚会

紧急集合 / 聚会

题目大意:

给出一个无向图,每一次给出图中的三个点,求离三个点距离之和最小的点。

解决方法:

倍增LCA。

首先我们两两点之间求出LCA,那么离他们距离之和最近的点就是三个点中深度最深的点,想一想为什么?

我们假设存在一个点离三个点距离之和更近且深度更浅,那么我们将它的深度往下走一个,一定会有两个点距离-1,一个点+1,所以往下移更靠近正解opt,那么我们就可以得出我们上述结论合法。

而关于距离之和,由于dis(u,v)=dep[u]+dep[v]-dep[lca(u,v)],那么我们把三个点两两之间∑一下再除以二就能得到答案了,式子就不推了。。。

dis=dep[x]+dep[y]+dep[z]-dep[lca(x,y)]-dis[lca(y,z)]-dis[lca(x,z)]

最后附上本题代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #define maxn 500000
  4 using namespace std;
  5 
  6 int n,m,root,cnt;
  7 int head[maxn+5],dep[maxn+5],f[maxn+5][30];
  8 bool vis[maxn+5];
  9 struct EDGE
 10 {
 11     int nxt,to;
 12 };
 13 EDGE edge[maxn*2+5];
 14 
 15 int max(int x,int y)
 16 {
 17     if(dep[x]>=dep[y])
 18     {
 19         return x;
 20     }
 21     return y;
 22 }
 23 int abs(int x)
 24 {
 25     if(x<0)
 26     {
 27         return -x;
 28     }
 29     return x;
 30 }
 31 void add(int x,int y)
 32 {
 33     edge[++cnt].to=y;
 34     edge[cnt].nxt=head[x];
 35     head[x]=cnt;
 36 }
 37 void pre_fir(int u,int fa)
 38 {
 39     dep[u]=dep[fa]+1;
 40     for(int i=0;i<=25;i++)
 41     {
 42         f[u][i+1]=f[f[u][i]][i];
 43     }
 44     for(int i=head[u];i;i=edge[i].nxt)
 45     {
 46         if(edge[i].to==fa)
 47         {
 48             continue;
 49         }
 50         f[edge[i].to][0]=u;
 51         pre_fir(edge[i].to,u);
 52     }
 53 }
 54 int LCA(int x,int y)
 55 {
 56     if(dep[x]<dep[y])
 57     {
 58         swap(x,y);
 59     }
 60     for(int i=25;i>=0;i--)
 61     {
 62         if(dep[f[x][i]]>=dep[y])
 63         {
 64             x=f[x][i];
 65         }
 66         if(x==y)
 67         {
 68             return x;
 69         }
 70     }
 71     for(int i=25;i>=0;i--)
 72     {
 73         if(f[x][i]!=f[y][i])
 74         {
 75             x=f[x][i];
 76             y=f[y][i];
 77         }
 78     }
 79     return f[x][0];
 80 }
 81 int main()
 82 {
 83     scanf("%d%d",&n,&m);
 84     for(int i=1;i<=n-1;i++)
 85     {
 86         int x,y;
 87         scanf("%d%d",&x,&y);
 88         add(x,y);
 89         add(y,x);
 90         vis[y]=1;
 91     }
 92     for(int i=1;i<=n;i++)
 93     {
 94         if(vis[i]==0)
 95         {
 96             root=i;
 97             break;
 98         }
 99     }
100     dep[root]=1;
101     pre_fir(root,0);
102     for(int i=1;i<=m;i++)
103     {
104         int x,y,z;
105         scanf("%d%d%d",&x,&y,&z);
106         int ans1=LCA(x,y),ans2=LCA(y,z),ans3=LCA(x,z);
107         int ans=max(max(ans1,ans2),ans3);
108         printf("%d %d\n",ans,dep[x]+dep[y]+dep[z]-dep[ans1]-dep[ans2]-dep[ans3]);
109     }
110     return 0;
111 }

猜你喜欢

转载自www.cnblogs.com/yufenglin/p/10579901.html