树上三点间距离

这一生的挚爱 提交于 2019-12-03 07:29:21

P4281 [AHOI2008]紧急集合 / 聚会

这道题很卡常

但用一些优化 可过

问题

求一点到 三个不同点的距离最小

输出这个点 和这个距离

#define sum(a,b,c) (depth[a] + depth[b] + depth[c])
t,ab = lca(a,b),ac = lca(a,c),bc = lca(b,c);
if(ab == ac) t = bc;
if(ab == bc) t = ac;
if(ac == bc) t = ab;
printf("%d %d\n",t,sum(a,b,c) - sum(ab,ac,bc));

感性理解下

倍增的一些优化

for(reg i = 1;i <= n;i++) 
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
        
inline int lca(int a,int b)
{
    if(depth[a] < depth[b]) swap(a,b);
    while(depth[a] > depth[b]) a = fa[a][lg[depth[a] - depth[b]] - 1];
    if(a == b) return a;
    for(reg i = lg[depth[a]];i >= 0;i--)
        if(fa[a][i] != fa[b][i])
            a = fa[a][i],b = fa[b][i];
    return fa[a][0];
}

总结

  • 少函数,非递归函数用宏

  • \(lca\),提前处理\(log\)

  • register int

  • 变量名尽量小写,短

\(Code\)

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define reg register int
const int MAXN = 5e5 + 10;
int cnt,fa[MAXN][30],lg[MAXN],head[MAXN],depth[MAXN],n,m;
bool vis[MAXN];
struct node
{
    int v,next;
}edge[MAXN << 1];
template<typename T>
inline T Read(T Type)
{
    T x = 0;
    bool f = 0;
    char a = getchar();
    while(!isdigit(a)) {if(a == '-') f = 1;a = getchar();}
    while(isdigit(a)) x = (x << 1) + (x << 3) + a - '0',a = getchar();
    if(f) x *= -1;
    return x;
}
inline void addedge(int u,int v)
{
    edge[++cnt].v = v;
    edge[cnt].next = head[u];
    head[u] = cnt;
}
inline void prepare(int x)
{
    vis[x] = 1;
    for(reg i = head[x];i;i = edge[i].next)
    {
        int v = edge[i].v;
        if(vis[v]) continue;
        fa[v][0] = x;
        depth[v] = depth[x] + 1;
        prepare(v);
    }
}
inline int lca(int a,int b)
{
    if(depth[a] < depth[b]) swap(a,b);
    while(depth[a] > depth[b]) a = fa[a][lg[depth[a] - depth[b]] - 1];
    if(a == b) return a;
    for(reg i = lg[depth[a]];i >= 0;i--)
        if(fa[a][i] != fa[b][i])
            a = fa[a][i],b = fa[b][i];
    return fa[a][0];
}
#define sum(a,b,c) (depth[a] + depth[b] + depth[c])
int main()
{
    n = Read(1),m = Read(1);
    for(reg i = 1;i < n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v),addedge(v,u);
    }
    fa[1][0] = 1;
    for(reg i = 1;i <= n;i++) 
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
    prepare(1);
    for(reg i = 1;i <= lg[n];i++)
        for(reg j = 1;j <= n;j++)
            fa[j][i] = fa[fa[j][i - 1]][i - 1];
    int t,a,b,c,ab,ac,bc;
    for(reg i = 1;i <= m;i++)
    {
        a = Read(1),b = Read(1),c = Read(1),t,ab = lca(a,b),ac = lca(a,c),bc = lca(b,c);
        if(ab == ac) t = bc;
        if(ab == bc) t = ac;
        if(ac == bc) t = ab;
        printf("%d %d\n",t,sum(a,b,c) - sum(ab,ac,bc));
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!