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. Cesium开发添加entity无法显示

    无代码报错,js查询entity数量发现确实添加进去了.但是在底图上就是不显示. 有可能是跨域产生的问题.打开开发者工具Console栏.查看是不是存在跨域错误. 解决跨域后entity正常加载.

  2. JavaScript里的循环方法之forEach,for-in,for-of

    JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标 ...

  3. 排序(C语言实现)

    读数据结构与算法分析 插入排序 核心:利用的是从位置0到位置P都是已排序的 所以从位置1开始排序,如果当前位置不对,则和前面元素反复交换重新排序 实现 void InsertionSort(Eleme ...

  4. HWI的安装

    一.安装的过程 hwi的安装过程: 1.解压src源码包:tar -zvxf apache-hive-1.2.2-src.tar.gz 2.进到HWI目录下:cd /home/bigdata/apac ...

  5. PaaSoo云通讯-印度市场机遇与挑战并存

    2019年4月16日,由白鲸出海举办的2019中印互联网大会(Global Connects India)在印度新德里举行,这次的大会主要涵盖了出海主题峰会.B2B展会.中印互联网高层圆桌等模块. 众 ...

  6. #Ubuntu 18.04 安装tensorflow-gpu 1.9

    参考 https://tensorflow.google.cn/install/install_linux http://nvidia.com/cuda http://developer.nvidia ...

  7. node项目设置环境变量

    在UNIX系统中: $ NODE_ENV=production node app 在Windows中: $ set NODE_ENV=production $ node app 这些环境变量会出现在程 ...

  8. JS加密库

    作者声明:本博客中所写的文章,都是博主自学过程的笔记,参考了很多的学习资料,学习资料和笔记会注明出处,所有的内容都以交流学习为主.有不正确的地方,欢迎批评指正 本文主要是参考aicoder马伦老师的博 ...

  9. A Bug's Life(加权并查集)

    Description Background  Professor Hopper is researching the sexual behavior of a rare species of bug ...

  10. python 读取blob

    for num in range(76802): # if num == 0: # c[num] = imagedata[0:4] # d[num] = struct.unpack('i', c[nu ...