最近公共祖先(LCA)(题目)
Time Limit: 2000 ms Memory Limit: 256 MB
Description
Input
Output
Sample Input
15 5
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 1 2 2 3 3 4 4 5 5 6 6 7 7
1 2
8 11
5 8
8 15
4 6
Sample Output
1
5
4
7
3
HINT
Solution
这题是为了放上来提醒一下自己主席树还能这么用的。。不然主席树真的都快荒废了(我这是多久没打这种题了。。。)
首先一句话题意的话就是:给你两棵树,找一个标号最大的点,满足这个点是\(x\)在\(A\)树中祖先,也是\(y\)在\(B\)树中的祖先
因为有两棵树,我们要考虑两棵树共有的部分,所以可以从其中一棵树中的某些节点对另一棵树的贡献这样的角度来入手
一个简单粗暴的想法,我们将询问离线,对于每个\(A\)树上的点记录有关这个点的询问
然后在\(A\)树上dfs,然后每遍历到一个点,就把这个点对\(B\)树中点的贡献算上
具体一点就是,假如当前遍历到点\(u\),我们考虑\(u\)这个点是\(B\)树中哪些点的祖先,然后用这些\(u\)来更新这些点记录的祖先最大值(存在某个东西里面,这个值初始的时候应该要继承父节点的数据),因为我们是按照dfs的顺序来算贡献的,所以可以保证到目前为止,用来更新\(B\)树中贡献的,都是\(A\)树上\(u\)到根路径上的点,也就是\(u\)所有的祖先,那么我们只要对于\(u\)点中的每个询问,查询一下对应的在\(B\)树中的那个点对应的最大值就好了
然而我们要用什么东西来维护这个呢?
发现\(u\)能更新的应该是\(u\)这个点在\(B\)树中的子树内的所有点,那可以用\(dfs\)序搞成一个区间修改,那很容易就想到线段树了,接着发现我们要继承父节点的数据,那直接主席树爆搞一波即可
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN=2*(1e5)+10,SEG=MAXN*20*2;
struct xxx{
int y,nxt;
}a[MAXN*4];
struct Q{
int y,id;
Q(){}
Q(int _y,int _id){y=_y; id=_id;}
};
int h[MAXN],h1[MAXN],st[MAXN],lis[MAXN],ed[MAXN];
int rt[MAXN],ans[MAXN];
vector<Q> q[MAXN];
namespace Seg{/*{{{*/
int ch[SEG][2],mx[SEG],tag[SEG];
int tot,n;
void init(int _n){n=_n;}
int newnode(int pre){
ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1];
mx[tot]=mx[pre]; tag[tot]=tag[pre];
return tot;
}
void pushup(int x){mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);}
void givetag(int x,int delta){mx[x]=max(mx[x],delta); tag[x]=max(tag[x],delta);}
void _update(int pre,int &x,int l,int r,int lx,int rx,int delta){
x=newnode(pre);
if (l<=lx&&rx<=r){
givetag(x,delta); return;
}
int mid=lx+rx>>1;
if (l<=mid) _update(ch[pre][0],ch[x][0],l,r,lx,mid,delta);
if (r>mid) _update(ch[pre][1],ch[x][1],l,r,mid+1,rx,delta);
pushup(x);
}
void update(int pre,int x,int l,int r,int delta){_update(rt[pre],rt[x],l,r,1,n,delta);}
int _query(int x,int d,int lx,int rx){
if (!x) return 0;
if (lx==rx) return mx[x];
int mid=lx+rx>>1,ret=0;
pushup(x);
if (d<=mid) return max(_query(ch[x][0],d,lx,mid),tag[x]);
else return max(_query(ch[x][1],d,mid+1,rx),tag[x]);
}
int query(int x,int d){return _query(rt[x],d,1,n);}
}/*}}}*/
int n,m,tot,t;
void add(int x,int y,int *h);
void dfs(int x);
void dfs1(int fa,int x);
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,y;
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
memset(h1,-1,sizeof(h1));
tot=0;
for (int i=2;i<=n;++i){
scanf("%d",&x);
add(x,i,h1);
}
for (int i=2;i<=n;++i){
scanf("%d",&x);
add(x,i,h);
}
for (int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
q[x].push_back(Q(y,i));
}
Seg::init(n);
t=0;
dfs(1);
dfs1(0,1);
for (int i=1;i<=m;++i)
printf("%d\n",ans[i]);
}
void add(int x,int y,int *h){
a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;
}
void dfs(int x){//B
int u;
st[x]=++t; lis[t]=x;
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
dfs(u);
}
ed[x]=t;
}
void dfs1(int fa,int x){//A
Q tmp;
int u;
Seg::update(fa,x,st[x],ed[x],x);
for (int i=0;i<q[x].size();++i){
tmp=q[x][i];
ans[tmp.id]=Seg::query(x,st[tmp.y]);
}
for (int i=h1[x];i!=-1;i=a[i].nxt){
u=a[i].y;
dfs1(x,u);
}
}
最近公共祖先(LCA)(题目)的更多相关文章
- POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)
POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- 近期公共祖先(LCA)——离线Tarjan算法+并查集优化
一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...
- leetcode 236. 二叉树的最近公共祖先LCA(后序遍历,回溯)
LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百 ...
- 【lhyaaa】最近公共祖先LCA——倍增!!!
高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...
- [模板] 最近公共祖先/lca
简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- 最近公共祖先(LCA)模板
以下转自:https://www.cnblogs.com/JVxie/p/4854719.html 首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖 ...
- 最近公共祖先 lca (施工ing)
声明 咳咳,进入重难点的图论算法之一(敲黑板): 题目: 洛谷 P3379 先放标程,施工ing,以后补坑!!!(实在太难,一个模板这么长 [ 不过好像还是没有 AC自动机 长哎 ],注释都打半天,思 ...
随机推荐
- ES6的新特性(19)——Module 的语法
Module 的语法 概述 历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来.其他语言都有这项功能,比如 Ruby 的re ...
- myeclipse和ecplise中安装git插件的问题
我的myeclipse10.7和ecplise helis一直安装不了git插件,myeclipse中details说我的myeclipse少了team_features等之类文件,helis的情况大 ...
- 跨域写cookie
假设a站想往b站写cookie,那么目前有两种方案,参考如下: 第一种(使用jsonp): a站js代码如下: $.ajax({ url: 'http://www.b.com/jsonp.jsp?do ...
- Windows下IntelliJ IDEA中调试Spark Standalone
参考:http://dataknocker.github.io/2014/11/12/idea%E4%B8%8Adebug-spark-standalone/ 转载请注明来自:http://www.c ...
- 【Mark】Android应用开发SharedPreferences存储数据的使用方法
Android应用开发SharedPreferences存储数据的使用方法 SharedPreferences是Android中最容易理解的数据存储技术,实际上SharedPreferences处理的 ...
- SpringCloud——服务网关
1.背景 上篇博客<SpringCloud--Eureka服务注册和发现>中介绍了注册中心Eureka.服务提供者和服务消费者.这篇博客我们将介绍服务网关. 图(1) 未使用服务网关的做法 ...
- 虚拟机Centos设置静态IP
首先确保虚拟网卡(VMware Network Adapter VMnet8)是开启的,然后在windows的命令行里输入“ipconfig /all”,找到VMware Network Adapte ...
- 这可能是目前最全的Redis高可用技术解决方案总结
本文主要针对 Redis 常见的几种使用方式及其优缺点展开分析. 一.常见使用方式 Redis 的几种常见使用方式包括: Redis 单副本: Redis 多副本(主从): Redis Sentine ...
- Android Studio- 把项目提交到SVN中操作方法
第一步 下载SVN,下载完成之后,需要吧command line client tools点击修改安装 然后Crash Reporter点击选择取消安装 如果不进行该操作,则可能在C:\Program ...
- python之enumerate()学习
X = 'abcdefghijklmn' for (index,char) in enumerate(X): print (index, char) 利用enumerate()函数,可以在每次循环中同 ...