题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入输出格式

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

输入输出样例

输入样例#1:

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
输出样例#1:

4
4
1
4
4

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

样例说明:

该树结构如下:

第一次询问:2、4的最近公共祖先,故为4。

第二次询问:3、2的最近公共祖先,故为4。

第三次询问:3、5的最近公共祖先,故为1。

第四次询问:1、2的最近公共祖先,故为4。

第五次询问:4、5的最近公共祖先,故为4。

故输出依次为4、4、1、4、4。

思路:

  树剖。

来,上代码:

#include <cstdio>
#include <iostream>
#include <algorithm> #define maxn 500001 using namespace std; struct EdgeType {
int to,next;
};
struct EdgeType edge[maxn<<]; int if_z,n,m,s,num,f[maxn],deep[maxn];
int belong[maxn],size[maxn],cnt,head[maxn]; char Cget; inline void read_int(int &now)
{
now=,if_z=,Cget=getchar();
while(Cget>''||Cget<'')
{
if(Cget=='-') if_z=-;
Cget=getchar();
}
while(Cget>=''&&Cget<='')
{
now=now*+Cget-'';
Cget=getchar();
}
now*=if_z;
} inline void edge_add(int from,int to)
{
edge[++num].to=from,edge[num].next=head[to],head[to]=num;
edge[++num].to=to,edge[num].next=head[from],head[from]=num;
} void search(int now,int fa)
{
int pos=cnt++;
f[now]=fa,deep[now]=deep[fa]+;
for(int i=head[now];i;i=edge[i].next)
{
if(edge[i].to==fa) continue;
search(edge[i].to,now);
}
size[now]=cnt-pos;
} void search_(int now,int chain)
{
int pos=;
belong[now]=chain;
for(int i=head[now];i;i=edge[i].next)
{
if(edge[i].to==f[now]) continue;
if(size[pos]<size[edge[i].to]) pos=edge[i].to;
}
if(pos!=) search_(pos,chain);
else return ;
for(int i=head[now];i;i=edge[i].next)
{
if(edge[i].to==pos||edge[i].to==f[now]) continue;
search_(edge[i].to,edge[i].to);
}
} inline int lca(int x,int y)
{
while(belong[x]!=belong[y])
{
if(deep[belong[x]]<deep[belong[y]]) swap(x,y);
x=f[belong[x]];
}
if(deep[x]<deep[y]) return x;
else return y;
} int main()
{
read_int(n),read_int(m),read_int(s);
int from,to;
for(int i=;i<n;i++)
{
read_int(from),read_int(to);
edge_add(from,to);
}
search(s,),cnt=,search_(s,s);
for(int i=;i<=m;i++)
{
read_int(from),read_int(to);
printf("%d\n",lca(from,to));
}
return ;
}

附,70分暴力找lca:

#include <cstdio>
#include <algorithm> #define maxn 500001 using namespace std; struct EdgeType {
int to,next;
};
struct EdgeType edge[maxn<<]; int f[maxn],head[maxn],num;
int n,m,s,if_z,dfn[maxn],cnt; char Cget; inline void read_int(int &now)
{
now=,if_z=,Cget=getchar();
while(Cget>''||Cget<'')
{
if(Cget=='-') if_z=-;
Cget=getchar();
}
while(Cget>=''&&Cget<='')
{
now=now*+Cget-'';
Cget=getchar();
}
now*=if_z;
} inline void edge_add(int from,int to)
{
edge[++num].to=from,edge[num].next=head[to],head[to]=num;
edge[++num].to=to,edge[num].next=head[from],head[from]=num;
} void search(int now,int fa)
{
dfn[now]=++cnt,f[now]=fa;
for(int i=head[now];i;i=edge[i].next)
{
if(edge[i].to==fa) continue;
search(edge[i].to,now);
}
} inline int lca(int x,int y)
{
if(dfn[x]<dfn[y]) swap(x,y);
while(dfn[x]>dfn[y]) x=f[x];
while(dfn[y]>dfn[x]) y=f[y];
return y;
} int main()
{
read_int(n),read_int(m),read_int(s);
int from,to;
for(int i=;i<n;i++)
{
read_int(from),read_int(to);
edge_add(from,to);
}
search(s,);
for(int i=;i<=m;i++)
{
read_int(from),read_int(to);
printf("%d\n",lca(from,to));
}
return ;
}

AC日记——【模板】最近公共祖先(LCA)洛谷 P3379的更多相关文章

  1. [模板] 最近公共祖先/lca

    简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...

  2. AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345

    [ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...

  3. AC日记——[JLOI2014]松鼠的新家 洛谷 P3258

    题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...

  4. AC日记——[USACO15DEC]最大流Max Flow 洛谷 P3128

    题目描述 Farmer John has installed a new system of  pipes to transport milk between the  stalls in his b ...

  5. AC日记——[USACO10MAR]仓配置Barn Allocation 洛谷 P1937

    [USACO10MAR]仓配置Barn Allocation 思路: 贪心+线段树维护: 代码: #include <bits/stdc++.h> using namespace std; ...

  6. AC日记——[HNOI2010]BOUNCE 弹飞绵羊 洛谷 P3203

    [HNOI2010]BOUNCE 弹飞绵羊 思路: SBlct: 代码: #include <bits/stdc++.h> using namespace std; #define max ...

  7. AC日记——斐波那契数列 洛谷 P1962

    斐波那契数列 思路: 矩阵快速幂: 来,上代码: #include <cstdio> #include <cstring> #include <iostream> ...

  8. AC日记——[USACO09JAN]全流Total Flow 洛谷 P2936

    题目描述 Farmer John always wants his cows to have enough water and thus has made a map of the N (1 < ...

  9. AC日记——[USACO11DEC]牧草种植Grass Planting 洛谷 P3038

    题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...

  10. AC日记——让我们异或吧 洛谷 P2420

    题目描述 异或是一种神奇的运算,大部分人把它总结成不进位加法. 在生活中…xor运算也很常见.比如,对于一个问题的回答,是为1,否为0.那么: (A是否是男生 )xor( B是否是男生)=A和B是否能 ...

随机推荐

  1. (69)zabbix监控惠普打印机

    假设公司有多个楼层或者分布在不同楼,打印机自然分布很广泛,打印机缺少油墨或者卡纸了,都需要员工找IT部门.我们使用zabbix对打印机进行监控,一旦缺少油墨,zabbix发出报警,it人员能够及时更换 ...

  2. JQ之$.ajax()方法以及ajax跨域请求

    AJAX(Asynchronous javascript AND xml :异步javascript和xml):是一种创建交互式网页应用的网页开发技术.AJAX可以在不重新加载整个页面的情况下与服务器 ...

  3. java的面向对象 (2013-09-30-163写的日志迁移

    1)面向对象的特征 1. 抽象:(从java方面来说抽象大多数人还是把它作为java中的一种特征来对待) 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象包括 ...

  4. Python9-事件及队列-day37

    信号量 from multiprocessing import Process from multiprocessing import Semaphore import time import ran ...

  5. cpu位图

    SMP处理器中要用到cpu位图,用来维护系统内CPU的状态信息,具有代表性的有: cpu_possible_map.cpu_online_map.cpu_present_map. static DEC ...

  6. LeetCode(206) Reverse Linked List

    题目 Reverse a singly linked list. click to show more hints. Hint: A linked list can be reversed eithe ...

  7. URLError与HTTPError

    urllib2 的异常错误处理 在我们用urlopen或opener.open方法发出一个请求时,如果urlopen或opener.open不能处理这个response,就产生错误. 这里主要说的是U ...

  8. c#中利用“|”运算组合多项

    前几天看到一段代码 int i = GetCount(para1 | para2); 咋一看有些莫名奇妙,怎么传参的时候带了个或运算,其实这里面是有讲究的,查阅了各方资料,QQ群里赖着大牛问,才搞明白 ...

  9. Hive安装步骤

    首先解压压缩包 然后进入bin 执行 ./hive 不过现在hive使用的是自己默认的数据库,不方便,可以通过配置使用MySQL数据库 创建hive-site.xml 粘贴一下内容 <confi ...

  10. loj2027 「SHOI2016」黑暗前的幻想乡

    矩阵树定理+模意义下整数高斯消元 #include <algorithm> #include <iostream> #include <cstring> #incl ...