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
This question is to remind myself that the chairman tree can still be used in this way. . Otherwise, the chairman tree is really going to be abandoned (I haven't asked this kind of question for a long time...)
The first sentence of the title is: give you two trees, find a point with the largest label, satisfy this point is \(x\) in the \(A\) tree ancestor, also \(y\) in \(B\ ) ancestors in the tree
Because there are two trees, we need to consider the parts that both trees have in common, so we can start from the perspective of the contribution of some nodes in one of the trees to the other tree.
A simple and crude idea, we will ask offline, for each point on the \(A\) tree record the query about this point
Then dfs on the \(A\) tree, and then each time a point is traversed, the contribution of this point to the point in the \(B\) tree is counted
具体一点就是,假如当前遍历到点\(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);
}
}