习题:Company(LCA)

题目

传送门

思路

一个性质,一群节点的lca一定是其中dfn最小的的节点和dfn最大的节点的lca

用线段树维护区间dfn的最大值和最小值即可

代码

#include<iostream>
#include<vector>
using namespace std;
#define pii pair<int,int>
#define x first
#define y second
namespace lst
{
    struct node
    {
        int l,r;
        pii maxx;
        pii minn;
        //x表示值,y表示位置
    }tre[400005];
    void build(int l,int r,int k)
    {
        tre[k].l=l;
        tre[k].r=r;
        if(l==r)
            return;
        int mid=(l+r)>>1;
        build(l,mid,k<<1);
        build(mid+1,r,k<<1|1);
    }
    void change(int pos,int val,int k)
    {
        if(tre[k].l>pos||pos>tre[k].r)
            return;
        if(tre[k].l==tre[k].r)
        {
            tre[k].maxx.x=tre[k].minn.x=val;
            tre[k].maxx.y=tre[k].minn.y=tre[k].l;
            return;
        }
        change(pos,val,k<<1);
        change(pos,val,k<<1|1);
        tre[k].maxx=max(tre[k<<1].maxx,tre[k<<1|1].maxx);
        tre[k].minn=min(tre[k<<1].minn,tre[k<<1|1].minn);
    }
    pii ask_min(int l,int r,int k)
    {
        if(tre[k].l>r||l>tre[k].r)
            return make_pair(1<<30,0);
        if(l<=tre[k].l&&tre[k].r<=r)
            return tre[k].minn;
        return min(ask_min(l,r,k<<1),ask_min(l,r,k<<1|1));
    }
    pii ask_max(int l,int r,int k)
    {
        if(tre[k].l>r||l>tre[k].r)
            return make_pair(0,0);
        if(l<=tre[k].l&&tre[k].r<=r)
            return tre[k].maxx;
        return max(ask_max(l,r,k<<1),ask_max(l,r,k<<1|1));
    }
}
using namespace lst;
int n,q,cnt;
int dfn[100005];
int dep[100005],dp[100005][25];
vector<int> g[100005];
void dfs(int u,int fa)
{
    dfn[u]=++cnt;
    change(u,dfn[u],1);
    dep[u]=dep[fa]+1;
    for(int i=1;i<=20;i++)
        dp[u][i]=dp[dp[u][i-1]][i-1];
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(v!=fa)
        {
            dp[v][0]=u;
            dfs(v,u);
        }
    }
}
int lca(int u,int v)
{
    if(u==v)
        return u;
    if(dep[u]>dep[v])
        swap(u,v);
    for(int i=20;i>=0;i--)
        if(dep[u]<=dep[dp[v][i]])
            v=dp[v][i];
    if(u==v)
        return u;
    for(int i=20;i>=0;i--)
        if(dp[u][i]!=dp[v][i])
        {
            u=dp[u][i];
            v=dp[v][i];
        }
    return dp[u][0];
}
int solve(int l,int r,int cnt)
{
    if(cnt==l)
    {
        pii t1=ask_max(l+1,r,1);
        pii t2=ask_min(l+1,r,1);
        return lca(t1.y,t2.y);
    }
    else if(cnt==r)
    {
        pii t1=ask_max(l,r-1,1);
        pii t2=ask_min(l,r-1,1);
        return lca(t1.y,t2.y);
    }
    else
    {
        pii t1=ask_max(l,cnt-1,1);
        pii t2=ask_min(l,cnt-1,1);
        pii s1=ask_max(cnt+1,r,1);
        pii s2=ask_min(cnt+1,r,1);
        return lca(lca(t1.y,t2.y),lca(s1.y,s2.y));
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>q;
    build(1,n,1);
    for(int i=2,u;i<=n;i++)
    {
        cin>>u;
        g[i].push_back(u);
        g[u].push_back(i);
    }
    dep[0]=-1;
    dfs(1,0);
    for(int i=1,l,r;i<=q;i++)
    {
        cin>>l>>r;
        pii t1=ask_max(l,r,1),t2=ask_min(l,r,1);
        int lca1=solve(l,r,t1.y),lca2=solve(l,r,t2.y);
        if(dep[lca1]>dep[lca2])
            cout<<t1.y<<' '<<dep[lca1]<<'\n';
        else
            cout<<t2.y<<' '<<dep[lca2]<<'\n';
    }
    return 0;
}
posted @ 2020-08-24 10:59  loney_s  阅读(122)  评论(0)    收藏  举报