luoguP4281[AHOI2008]紧急集合 / 聚会

最近复习lca,布置的三道题中最后一道就是这个紫题。当时看到是紫题吓了一跳(果然是我太弱了QAQ)然后仔细读了几遍题,发现这就是普通的lca嘛 (太水了) 其中变化的只有要分别求三者的lca。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
struct kh{
    int t, nxt;
}e[2*500001];
int dep[500001], f[500001][22], tot, head[500001], lo[500001], t;
ll ans = 0;
void add(int x,int y)
{
     e[++tot].t = y;
    e[tot].nxt = head[x];
    head[x] = tot;
}
void dfs(int fa, int h)
{
    dep[fa] = dep[h] + 1;
    f[fa][0] = h;
    for(int i = 1;(1<<i) <= dep[fa];i++)
      f[fa][i] = f[f[fa][i-1]][i-1];
    for(int i = head[fa];i;i = e[i].nxt)
      if(e[i].t != h)
        dfs(e[i].t,fa);
}
int lca(int x,int y)
{
    if(dep[x] < dep[y])
      swap(x,y);
    while(dep[x] > dep[y])
      x = f[x][lo[dep[x] - dep[y]] - 1];
    if(x == y)
      return x;
    for(int k= lo[dep[x]] - 1;k >= 0;k--)
      if(f[x][k] != f[y][k])
        x = f[x][k], y = f[y][k];
    return f[x][0];
}
int n, m, s, x, y, a, b, c;
int main()
{
    scanf("%d %d", &n, &m);
    for(int i = 1;i <= n - 1;i++)
    {
        scanf("%d %d", &a, &b);
        add(a, b);
        add(b, a);
    }
    dfs(1,0);
    for(int i = 1;i <= n;i++)
    lo[i] = lo[i - 1] + (1<<lo[i - 1] == i);
    for(int i = 1;i <= m;i++)
    {
        ans = 0;
        scanf("%d %d %d", &a, &b, &c);
        int t1 = lca(a,b);//分别求三者lca
        int t2 = lca(a,c);
        int t3 = lca(b,c);
        if(t1 == t2)
        t = t3;
        else if(t1 == t3)
        t = t2;
        else if(t2 == t3)
        t = t1;
        ans = dep[a] + dep[b] + dep[c] - dep[t1] - dep[t2] - dep[t3];
        printf("%d %lld\n", t, ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/jiqimin/p/10628415.html

时间: 2024-08-26 00:30:55

luoguP4281[AHOI2008]紧急集合 / 聚会的相关文章

「AHOI2008」「LuoguP4281」紧急集合 / 聚会(LCA

题目描述 欢乐岛上有个非常好玩的游戏,叫做“紧急集合”.在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币. 参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费).地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系).当集合号吹响后,每组成员之间迅速联系,了解到自己组所有成员所

[AHOI2008]紧急集合 / 聚会

紧急集合 / 聚会 题目大意: 给出一个无向图,每一次给出图中的三个点,求离三个点距离之和最小的点. 解决方法: 倍增LCA. 首先我们两两点之间求出LCA,那么离他们距离之和最近的点就是三个点中深度最深的点,想一想为什么? 我们假设存在一个点离三个点距离之和更近且深度更浅,那么我们将它的深度往下走一个,一定会有两个点距离-1,一个点+1,所以往下移更靠近正解opt,那么我们就可以得出我们上述结论合法. 而关于距离之和,由于dis(u,v)=dep[u]+dep[v]-dep[lca(u,v)]

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

题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有 n 个等待点,有 n?1 条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币. 参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费).地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系).当集合号吹响后,每组成员之间迅速联系,了解

AHOI2008 紧急集合 树上倍增

AHOI2008 紧急集合 题目传送 sol: 如果只有两个点,那么显然目的地就是在他们二者路径上的任意一点. 现在有三个点,考虑两两的路径和lca,发现肯定有两对求得的lca相同,另外一对的lca深度比那两对的lca深度大. 这个深度大一些的那个lca就是目的地(最近点),最小距离就是三者两两距离的二分之一. 所以直接树上倍增即可. #include<bits/stdc++.h> #define IL inline #define RG register #define DB double

[AHOI2008] 紧急集合

Description 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币. 参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费).地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系).当集合号吹响后,每组成员之间迅速联系

[bzoj1787][Ahoi2008]紧急集合

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 Output 5 2 2 5 4 1 6 0 HINT Solution 对

【BZOJ1832】【AHOI2008】聚会 倍增lca

这道题写不了tarjanlca. 50W的询问,也就是150W次lca查询,每次加三条边,内存妥妥要爆. 只能退求logn的倍增lca了. sad story. 还好一遍AC. 题解: 就是发现每次询问三个点之间有唯一的路径集,那么我们选其中两个取lca,然后另一个点自己走到这个lca, 就可以贪心取得答案. 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorit

BZOJ 1787 AHOI2008 紧急集合 倍增LCA

题目大意:给定一棵树,多次询问到三个点距离之和最小的点和距离 首先易知到两个点距离之和最小的点一定在两点间的路径上 于是到三个点距离之和最小的点一定在两两之间路径的交点上 然后很容易就会知道这个交点一定是其中两个点的LCA(其实是我不会证) 此外为什么不会是三个点共同的LCA呢?因为三个点共同的LCA一定是至少一对点的LCA 证明略(其实我也不会证) 然后就是枚举两两之间的LCA 求一下距离 取最小即可 然后就是倍增LCA的问题了 我的倍增LCA怎么又挂了 还能不能写对了0.0 #include

luogu4281

P4281 [AHOI2008]紧急集合 / 聚会 题目描述 欢乐岛上有个非常好玩的游戏,叫做“紧急集合”.在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币. 参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费).地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系).当集合号