【BZOJ-1787】Meet紧急集合 倍增LCA

1787: [Ahoi2008]Meet 紧急集合

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 2259  Solved: 1023
[Submit][Status][Discuss]

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

Source

Day1

Solution

水题,随便倍增一下求LCA就可以

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
#define maxn 500010
int n,m,deep[maxn],father[maxn][21];
struct EdgeNode{int next,to;}edge[maxn<<1];
int head[maxn],cnt;
void add(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void insert(int u,int v) {add(u,v); add(v,u);}
void DFS(int now,int last)
{
    for (int i=1; i<=20; i++)
        if (deep[now]>=(1<<i)) father[now][i]=father[father[now][i-1]][i-1];
        else break;
    for (int i=head[now]; i; i=edge[i].next)
        if (edge[i].to!=last)
            {
                father[edge[i].to][0]=now;
                deep[edge[i].to]=deep[now]+1;
                DFS(edge[i].to,now);
            }
}
int LCA(int x,int y)
{
    if (deep[x]<deep[y]) swap(x,y);
    int dd=deep[x]-deep[y];
    for (int i=0; i<=20; i++)
        if ((1<<i)&dd) x=father[x][i];
    for (int i=20; i>=0; i--)
        if (father[x][i]!=father[y][i])
            x=father[x][i],y=father[y][i];
    if (x==y) return x; return father[x][0];
}
int Dist(int u,int v)
{
    int lca=LCA(u,v);
    return deep[u]+deep[v]-(deep[lca]<<1);
}
int ans,rt;
int main()
{
    n=read(); m=read();
    for (int u,v,i=1; i<=n-1; i++)
        u=read(),v=read(),insert(u,v);
    DFS(1,0);
    for (int x,y,z,i=1; i<=m; i++)
        {
            x=read(),y=read(),z=read();
            int fxy=LCA(x,y),fyz=LCA(y,z),fxz=LCA(x,z);
            rt=(fxy==fyz)? fxz : fxy==fxz? fyz : fxy;
            ans=Dist(x,rt)+Dist(y,rt)+Dist(z,rt);
            printf("%d %d\n",rt,ans);
        }
    return 0;
}

在学校被***毒的不能自拔,感觉已经不想在班里待下去了

时间: 2024-07-29 10:24:32

【BZOJ-1787】Meet紧急集合 倍增LCA的相关文章

BZOJ 1787 AHOI2008 紧急集合 倍增LCA

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

bzoj 1787 Meet 紧急集合

Meet 紧急集合 这个题是在脖子oj(清北某奆佬给起的名字)八中oj(大视野在线评测)上的. 给出bzoj链接. 这个题还是求最近公共祖先的问题. 而该题不同于别的题,它是需要求三个点的最近公共祖先. 我们就需要求出三个点两两之间的LCA. 而这三个LCA之间,必有两个是相同的. 如果两个点相同,那另一点就是那三个点的LCA. 如果三个点都相同,那么该点就是那三个点的LCA. 最后还需要统计走过的边的长度. 三个点都相同的情况很好搞,就是计算三个点与那个LCA的深度差,加起来就是答案. 但是两

【bzoj1787】[Ahoi2008]Meet 紧急集合 倍增LCA

题目描述 输入 输出 样例输入 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6 样例输出 5 2 2 5 4 1 6 0 题解 倍增LCA 首先有集合点必定在三点中两个点的LCA处,大概画一下就看出来了. 然后有x到y的距离为deep[x]+deep[y]-2*deep[lcaxy] 那么x.y.z三点到lcaxy的距离为deep[x]+deep[y]-2*deep[lcaxy]+deep[lcaxy]+deep[x]-deep[lcaxyz] 到

BZOJ 1787 AHOI 2008 Meet 紧急集合 倍增LCA

题目大意:给出一棵树,在上满找三个点,问那个点到这三个点的距离和最短. 思路:可以证明,这个店必然是这三个点之间两个的LCA,然后枚举就可以了. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1000010 #define INF 0x3f3f3f3f using namespace std; int points

BZOJ 2791 Poi2012 Rendezvous 倍增LCA

题目大意:给定一棵内向森林,多次给定两个点a和b,求点对(x,y)满足: 1.从a出发走x步和从b出发走y步会到达同一个点 2.在1的基础上如果有多解,那么要求max(x,y)最小 3.在1和2的基础上如果有多解,那么要求min(x,y)最小 4.如果在1.2.3的基础上仍有多解,那么要求x>=y 因此那个x>=y是用来省掉SPJ的,不是题目要求- - 容易发现: 如果a和b不在同一棵内向树上,显然无解,否则一定有解 定义根为从一个点出发能走到的第一个环上点,如果a和b的根相同,则到达LCA是

BZOJ 3732 Network Kruskal+倍增LCA

题目大意:给定一个n个点m条边的无向连通图,k次询问两点之间所有路径中最长边的最小值 NOIP2013 货车运输,几乎就是原题...只不过最小边最大改成了最大边最小... 首先看到最大值最小第一反应二分答案 但是二分答案O(kmlogn)明显做不了 这里我们考虑最小生成树 先生成一棵最小生成树,然后每次询问利用倍增LCA求出路径上的最大权值即可 本蒟蒻居然把LCA写挂了... 而且样例还过了... 伤不起啊... 90%达成 剩下一道刷点啥呢... #include<cstdio> #incl

[bzoj1787][Ahoi2008]Meet 紧急集合(lca)

传送门 可以看出,三个点两两之间的lca会有一对相同,而另一个lca就是聚集点. 然后搞搞就可以求出距离了. ——代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define MAXN 1000001 5 6 using namespace std; 7 8 int n, m, cnt, ans; 9 int head[MAXN], to[MAXN], next[MAXN], de

BZOJ 2286 SDOI2011 消耗战 倍增LCA+单调栈

题目大意:给定一棵树,边上有边权,m次询问,每次选定一些关键点,求将1号节点与所有关键点都切断所需的最小花销 关键点的总数<=50W 首先我们考虑暴力想法 令f[x]表示切断以x为根的子树中所有关键点的最小花销 g[x]表示x是不是关键点 那么对于x的每个子节点y有f[x]=Σmin(g[y]?INF:f[y],Distance(x,y) ) 这样每次暴力做一遍树形DP,时间复杂度是O(n*m)的 现在由于每次询问的点数不一定会达到n的级别,对所有节点进行DFS非常浪费 我们可以将询问的关键点拿

bzoj 1787 [Ahoi2008]Meet 紧急集合(1832 [AHOI2008]聚会)

1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1841  Solved: 857[Submit][Status][Discuss] 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 Source Day1