luogu P4281 [AHOI2008]紧急集合 / 聚会

这道题第一眼看

LCA啊

三个点,两两求LCA,一定有两个是相同的

另一个点一定深度最小,所以更优

用一个depth数组记录每个点的深度,加加减减就得出来了

emmmm

很简单

(gg布置的另两道题,一道LCA板子不用说,另一道也是板子,就多了加加减减

(这道虽然是紫题但也挺水的

#include<cstdio>
#include<cmath>
#include<algorithm>
#define sev en
using namespace std;
#define N 500010

struct edgee{
  int nxt,to;
}edge[N << 1];

int head[N];
int depth[N];
int fa[N][31];
int cnt;

void add(int x,int y){
  edge[++cnt].to = y;
  edge[cnt].nxt = head[x];
  head[x] = cnt;
}

void dfs(int x,int now){
  depth[x] = now;
  for(int i = head[x];i;i = edge[i].nxt){
    int v = edge[i].to;
    if(!depth[v]){
      fa[v][0] = x;
      dfs(v,now + 1);
    }
  }
}

int LCA(int a,int b){
  if(depth[a] < depth[b])
    swap(a,b);
  for(int j = 30;j >= 0;j--)
    if(depth[a] - (1<<j) >= depth[b])
      a = fa[a][j];
  if(a != b){
    for(int j = 30;j >= 0;j--){
      if(fa[a][j] != fa[b][j]){
    a = fa[a][j];
    b = fa[b][j];
      }
    }
    a = fa[a][0];
  }
  return a;
}

int main(){
  int n,m;
  scanf("%d%d",&n,&m);
  for(int i = 1;i < n;i++){
    int u,v;
    scanf("%d%d",&u,&v);
    add(u,v);
    add(v,u);
  }
  dfs(1,0);
  for(int j = 1;j < 30;j++)
    for(int i = 1;i <= n;i++)
      fa[i][j] = fa[fa[i][j - 1]][j - 1];
  for(int i = 1;i <= m;i++){
    long long ans = 0;
    int rt;
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    int rt1 = LCA(a,b);
    int rt2 = LCA(b,c);
    int rt3 = LCA(a,c);
    if(rt1 == rt2)
      rt = rt3;
    else if(rt2 == rt3)
      rt = rt1;
    else if(rt1 == rt3)
      rt = rt2;
    ans = depth[a] + depth[b] + depth[c] - depth[rt1] - depth[rt2] - depth[rt3];
    printf("%d %lld\n",rt,ans);
  }
  return 0;
}

end.

(这题解写的也好水嘤嘤嘤

posted @ 2019-03-22 21:03  ./seven  阅读(176)  评论(0编辑  收藏  举报