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)(题目)的更多相关文章

  1. POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)

    POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...

  2. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  3. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)

    POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...

  4. 近期公共祖先(LCA)——离线Tarjan算法+并查集优化

    一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...

  5. leetcode 236. 二叉树的最近公共祖先LCA(后序遍历,回溯)

    LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百 ...

  6. 【lhyaaa】最近公共祖先LCA——倍增!!!

    高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...

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

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

  8. 最近公共祖先LCA(Tarjan算法)的思考和算法实现

    LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...

  9. 最近公共祖先(LCA)模板

    以下转自:https://www.cnblogs.com/JVxie/p/4854719.html 首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖 ...

  10. 最近公共祖先 lca (施工ing)

    声明 咳咳,进入重难点的图论算法之一(敲黑板): 题目: 洛谷 P3379 先放标程,施工ing,以后补坑!!!(实在太难,一个模板这么长 [ 不过好像还是没有 AC自动机 长哎 ],注释都打半天,思 ...

随机推荐

  1. 2019展望计划(Lamica 2019-Year Plan):

    1,家人身体健康.2,好好上课,考试顺利,不要挂科.3,PETS3 9月份 杭州 一定要过.4,PETS3通过后,进军日语N3-N2.5,在杭州找一份合适的工作(底线6K).6,在杭州交到新朋友.7, ...

  2. .net core 2.1.3可能引发Could not load file or assembly XXXXX的错误

    参考文档: https://github.com/aspnet/Home/issues/3503 写在前面 感觉自己现在干的活离开发越来越远了啊,不过也很好,每天能学到不少东西,中文的,英文的,永远也 ...

  3. New York Comic Con 2013 - 2013年纽约动漫展

    New York Comic Con - 2013年纽约动漫展 New York Comic Con is the largest pop culture event on the East Coas ...

  4. 实现属于自己的TensorFlow(二) - 梯度计算与反向传播

    前言 上一篇中介绍了计算图以及前向传播的实现,本文中将主要介绍对于模型优化非常重要的反向传播算法以及反向传播算法中梯度计算的实现.因为在计算梯度的时候需要涉及到矩阵梯度的计算,本文针对几种常用操作的梯 ...

  5. 全国城市一卡通一级TSM平台业务架构及意义

    [导读]TSM平台是一种具有鲜明行业属性的平台,因此,各行业都建立了本行业的TSM平台.为促进城市一卡通行业移动支付的快速发展,住房和城乡建设部也建立了全国城市一卡通行业一级TSM平台. 作为住建部标 ...

  6. Java JDK安装及环境配置

    转载:https://jingyan.baidu.com/article/6dad5075d1dc40a123e36ea3.html 环境变量配置: 系统变量→新建 JAVA_HOME 变量 . 变量 ...

  7. 寒假作业2:简化电梯设计elevator

    Github仓库地址:hua-kui 寒假学习计划:学习计划 - 题目背景 一栋10层的大楼(楼层编号1-10),设有一台无限载重的电梯,初始时电梯停在1层.电梯移动1层的耗时为1,在某一层停靠的耗时 ...

  8. HDU 5159 Card

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5159 题解: 考虑没一个数的贡献,一个数一次都不出现的次数是(x-1)^b,而总的排列次数是x^b, ...

  9. 使用RStudio学习一个简单神经网络

    数据准备 1.收集数据 UC Irvine Machine Learning Repository-Concrete Compressive Strength Data Set 把下载到的Concre ...

  10. 利用canvas对上传图片进行上传前压缩

    利用谷歌调式工具发现,图片大小直接影响着首屏加载时间. 且考虑到后期服务端压力,图片压缩特别必要. 本文是前端利用canvas实现图片.参考文章:https://www.cnblogs.com/007 ...