最近公共祖先(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\)树上的点记录有关这个点的询问

扫描二维码关注公众号,回复: 44669 查看本文章

  然后在\(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);
    }
}

猜你喜欢

转载自www.cnblogs.com/yoyoball/p/8909908.html