AHOI2008 紧急集合 树上倍增

AHOI2008 紧急集合

题目传送

sol:

如果只有两个点,那么显然目的地就是在他们二者路径上的任意一点。

现在有三个点,考虑两两的路径和lca,发现肯定有两对求得的lca相同,另外一对的lca深度比那两对的lca深度大。

这个深度大一些的那个lca就是目的地(最近点),最小距离就是三者两两距离的二分之一。

所以直接树上倍增即可。

#include<bits/stdc++.h>
#define IL inline
#define RG register
#define DB double
#define LL long long
using namespace std;

IL int gi() {
    RG int x=0,p=1; RG char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') p=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
    return x*p;
}

const int N=5e5+1;

int n,m,tot,len,npos,dep[N],head[N],f[N][20];

struct LCA{int pos,dis;}s[5];
struct EDGE{int next,to;}e[N<<1];

IL void make(int a,int b) {
    e[++tot]=(EDGE){head[a],b},head[a]=tot;
    e[++tot]=(EDGE){head[b],a},head[b]=tot;
}

void dfs(int x,int fx) {
    RG int i,y;
    for(i=head[x];i;i=e[i].next)
        if((y=e[i].to)!=fx)
            dep[y]=dep[x]+1,f[y][0]=x,dfs(y,x);
}

IL void multiply() {
    RG int i,j;
    for(i=1;i<20;++i)
        for(j=1;j<=n;++j)
            f[j][i]=f[f[j][i-1]][i-1];
}

IL LCA lca(int x,int y) {
    RG int i,dis=0;
    if(dep[x]<dep[y]) swap(x,y);
    for(i=19;i>=0;--i)
        if(dep[f[x][i]]>=dep[y]) dis+=1<<i,x=f[x][i];
    if(x==y) return (LCA){x,dis};
    for(i=19;i>=0;--i)
        if(f[x][i]!=f[y][i])
            dis+=1<<i+1,x=f[x][i],y=f[y][i];
    return (LCA){f[x][0],dis+2};
}

int main()
{
    RG int i,x,y,z;
    n=gi(),m=gi();
    for(i=1;i<n;++i) x=gi(),y=gi(),make(x,y);
    dep[1]=1,dfs(1,1),multiply();
    while(m--) {
        x=gi(),y=gi(),z=gi();
        s[1]=lca(x,y),s[2]=lca(y,z),s[3]=lca(x,z);
        len=(s[1].dis+s[2].dis+s[3].dis)/2;
        for(i=1,npos=0;i<=3;++i)
            if(dep[s[i].pos]>dep[npos]) npos=s[i].pos;
        printf("%d %d\n",npos,len);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Bhllx/p/11253269.html

时间: 2024-10-14 18:12:02

AHOI2008 紧急集合 树上倍增的相关文章

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

【树上倍增】【分类讨论】水果姐逛水果街Ⅱ

3305 水果姐逛水果街Ⅱ 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 水果姐第二天心情也很不错,又来逛水果街. 突然,cgh又出现了.cgh施展了魔法,水果街变成了树结构(店与店之间只有一条唯一的路径). 同样还是n家水果店,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样. cgh给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,

树上倍增 x

树上倍增. dfs序的做法: 思路: //f[i][j]表示dfs序中序号为i到序号为j的点之间深度最小的点的编号 dfs序[]//存0-...(id)编号 节点[]//存dfs序中所经过的节点号 dep[]//存走过的点所对应的点的深度 i : 1 2 3 4 5 6 7 ...... id[i] : (该点在节点编号中第一次出现的位置所对应的dfs序编号) //ans表示求u节点到i节点的最短距离... ans=f[id[u]][id[v]]; 至于代码……额……没写 树上倍增还能够用来求L

「Nescaf&#233;26」 Freda的传呼机 【树上倍增+图论】

题目: 为了随时与rainbow快速交流,Freda制造了两部传呼机.Freda和rainbow所在的地方有N座房屋.M条双向光缆.每条光缆连接两座房屋,传呼机发出的信号只能沿着光缆传递,并且传呼机的信号从光缆的其中一端传递到另一端需要花费t单位时间.现在Freda要进行Q次试验,每次选取两座房屋,并想知道传呼机的信号在这两座房屋之间传递至少需要多长时间.Freda和rainbow简直弱爆了有木有T_T,请你帮帮他们吧--N座房屋通过光缆一定是连通的,并且这M条光缆有以下三类连接情况:A:光缆不

图论-最近公共祖先-在线树上倍增

有关概念: 最近公共祖先(LCA,Lowest Common Ancestors):对于有根树T的两个结点u.v,最近公共祖先表示u和v的深度最大的共同祖先. 树上倍增是求LCA的在线算法(对于每一个询问输入后即计算) 思路: fa[i][j]表示编号为j的结点从下往上的第2i个祖先 即fa[0][j]表示j的父结点,递推式为fa[i][j]=fa[i-1][fa[i-1][j]],即j的第2i个祖先为j的第2i-1个祖先的第2i-1个祖先 另:不存在第2i个祖先(即2i超过j的深度)时,f[i

【bzoj4281】[ONTAK2015]Zwi?zek Harcerstwa Bajtockiego 树上倍增+LCA

题目描述 给定一棵有n个点的无根树,相邻的点之间的距离为1,一开始你位于m点.之后你将依次收到k个指令,每个指令包含两个整数d和t,你需要沿着最短路在t步之内(包含t步)走到d点,如果不能走到,则停在最后到达的那个点.请在每个指令之后输出你所在的位置. 输入 第一行包含三个正整数n,m,k(1<=m<=n<=1000000,1<=k<=1000000). 接下来n-1行,每行包含两个正整数x,y(1<=x,y<=n),描述一条树边. 接下来k行,每行两个整数d,t

HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow, and Blue are in war. The map of battlefield is a tree, which means that there are N nodes and (N – 1) edges that connect all the nodes. Each country

【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作,每次为一下三种之一: RELEASE x:对x执行一次感染: RECENTER x:把根节点改为x,并对原来的根节点执行一次感染: REQUEST x:询问x子树中所有节点感染代价的平均值. 输入 输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数.接下来n-1行,

BZOJ 4082 Wf2014 Surveillance 树上倍增

题目大意:给定一个n个点的环,有k个区间,要求选择最少的区间覆盖所有点 首先我们考虑链上版本,显然我们有一个贪心的做法: 从1号节点开始,每次选择能向后走的最远的区间,直到走完所有节点为止 正确性显然 但是到了环上版本我们却不能直接套用这个算法,因为环上不存在所谓的"1号节点" 因此我们这样做: 拆环后将序列倍增,把所有区间按照右端点从小到大排序 每个区间向这个区间右端点向后能走的最远的区间连一条边 这样我们会得到一棵树 从每个点可以用树上倍增求出最少向上走多少个点可以绕环走一圈 数据