Codeforces Contest 1062 problem E Company —— lca+主席树+dfs序

82 篇文章 1 订阅
25 篇文章 1 订阅

The company X has n employees numbered from 1 through n. Each employee u has a direct boss pu (1≤pu≤n), except for the employee 1 who has no boss. It is guaranteed, that values pi form a tree. Employee u is said to be in charge of employee v if u is the direct boss of v or there is an employee w such that w is in charge of v and u is the direct boss of w. Also, any employee is considered to be in charge of himself.

In addition, for each employee u we define it’s level lv(u) as follow:

lv(1)=0
lv(u)=lv(pu)+1 for u≠1
In the near future, there are q possible plans for the company to operate. The i-th plan consists of two integers li and ri, meaning that all the employees in the range [li,ri], and only they, are involved in this plan. To operate the plan smoothly, there must be a project manager who is an employee in charge of all the involved employees. To be precise, if an employee u is chosen as the project manager for the i-th plan then for every employee v∈[li,ri], u must be in charge of v. Note, that u is not necessary in the range [li,ri]. Also, u is always chosen in such a way that lv(u) is as large as possible (the higher the level is, the lower the salary that the company has to pay the employee).

Before any plan is operated, the company has JATC take a look at their plans. After a glance, he tells the company that for every plan, it’s possible to reduce the number of the involved employees exactly by one without affecting the plan. Being greedy, the company asks JATC which employee they should kick out of the plan so that the level of the project manager required is as large as possible. JATC has already figured out the answer and challenges you to do the same.

Input
The first line contains two integers n and q (2≤n≤100000, 1≤q≤100000) — the number of employees and the number of plans, respectively.

The second line contains n−1 integers p2,p3,…,pn (1≤pi≤n) meaning pi is the direct boss of employee i.

It is guaranteed, that values pi form a directed tree with the root of 1.

Each of the following q lines contains two integers li and ri (1≤li<ri≤n) — the range of the employees, involved in the corresponding plan.

Output
Print q lines, each containing two integers — the number of the employee which should be kicked from the corresponding plan and the maximum possible level of the project manager in that case.

If there are more than one way to choose that employee, print any of them.

Example
inputCopy
11 5
1 1 3 3 3 4 2 7 7 6
4 6
4 8
1 11
9 11
8 11
outputCopy
4 1
8 1
1 0
11 3
8 1
Note
In the example:
在这里插入图片描述
In the first query, we can choose whether 4 or 5 or 6 and the project manager will be 3.
In the second query, if we choose any employee other than the employee 8, the project manager will be 1. If we choose 8, the project manager will be 3. Since lv(3)=1>lv(1)=0, choosing 8 is the best strategy.

In the third query, no matter how we choose the employee, the project manager will always be 1.

In the fourth query, if we choose 9 or 10 then the project manager will be 3. If we choose 11 then the project manager will be 7. Since lv(7)=3>lv(3)=1, we choose 11 as the answer.

题意:

给你2-n的父亲,每一个节点的值就是它的深度,给你m个区间,让你去掉一个数,使得所有节点的lca深度最大。

题解:

最大lca肯定是两个最远点去掉一个,那我们就dfs标记每一个节点,用主席树两个最远的点和两个次远的点,由于在同一个节点下不需要考虑顺序的问题,那么就算它的节点标记是123或者321都无所谓。找到之后我们只需要看删掉哪一个最远点就好了

#include<bits/stdc++.h>
using namespace std;
#define N 100005
int head[N],fa[N][25],vis[N],cnt,dep[N],lv[N];
struct node
{
    int to,next;
}e[N<<1];
void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
//lca所属
void bfs()
{
    fa[1][0]=1;
    dep[1]=0;
    queue<int>Q;
    Q.push(1);
    while(!Q.empty())
    {
        int u,v;
        u=Q.front();
        Q.pop();
        for(int i=1;i<=16;i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int i=head[u];~i;i=e[i].next)
        {
            v=e[i].to;
            if(v==fa[u][0])
                continue;
            dep[v]=dep[u]+1;
            fa[v][0]=u;
            Q.push(v);
        }
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
//令x为深度较深的点
    for(int i=16;i>=0;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
//让x向上走到与y同一深度
    if(x==y)return x; //如果直接是lca,直接返回
    for(int i=16;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
//x,y同时向上走,直到父节点相同
    return fa[x][0]; //返回父节点
}
int dfn[N],anti[N];
int number;
//确定节点远近所属
void dfs(int x)
{
    dfn[x]=++number;
    anti[number]=x;
    for(int i=head[x];~i;i=e[i].next)
    {
        int ne=e[i].to;
        lv[ne]=lv[x]+1;
        dfs(ne);
    }
}
//主席树所属
int num[N*30],ls[N*30],rs[N*30],rt[N],tot;
void update(int l,int r,int root,int last,int pos)
{
    ls[root]=ls[last];
    rs[root]=rs[last];
    num[root]=num[last]+1;
    if(l==r)
        return ;
    int mid=l+r>>1;
    if(mid>=pos)
        update(l,mid,ls[root]=++tot,ls[last],pos);
    else
        update(mid+1,r,rs[root]=++tot,rs[last],pos);
}
int qmax(int l,int r,int root,int last)
{
    if(l==r)
        return l;
    int sum=num[rs[root]]-num[rs[last]];
    int mid=l+r>>1;
    if(sum>=1)
        return qmax(mid+1,r,rs[root],rs[last]);
    else
        return qmax(l,mid,ls[root],ls[last]);
}
int qsecmax(int l,int r,int root,int last,int val)
{
    if(l==r)
        return l;
    int sum=num[rs[root]]-num[rs[last]];
    int mid=l+r>>1;
    if(sum>=val)
        return qsecmax(mid+1,r,rs[root],rs[last],val);
    else
        return qsecmax(l,mid,ls[root],ls[last],val-sum);
}
int qmin(int l,int r,int root,int last)
{
    if(l==r)
        return l;
    int sum=num[ls[root]]-num[ls[last]];
    int mid=l+r>>1;
    if(sum>=1)
        return qmin(l,mid,ls[root],ls[last]);
    else
        return qmin(mid+1,r,rs[root],rs[last]);
}
int qsecmin(int l,int r,int root,int last,int val)
{
    if(l==r)
        return l;
    int sum=num[ls[root]]-num[ls[last]];
    int mid=l+r>>1;
    if(sum>=val)
        return qsecmin(l,mid,ls[root],ls[last],val);
    else
        return qsecmin(mid+1,r,rs[root],rs[last],val-sum);
}
int main()
{
    memset(head,-1,sizeof(head));
    int n,m;
    scanf("%d%d",&n,&m);
    int x;
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&x);
        add(x,i);
    }
    bfs(),dfs(1);
    for(int i=1;i<=n;i++)
        update(1,n,rt[i]=++tot,rt[i-1],dfn[i]);
    int l,r;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&l,&r);
        int maxn=anti[qmax(1,n,rt[r],rt[l-1])];
        int secmaxn=anti[qsecmax(1,n,rt[r],rt[l-1],2)];
        int minn=anti[qmin(1,n,rt[r],rt[l-1])];
        int secminn=anti[qsecmin(1,n,rt[r],rt[l-1],2)];
        int l1=lca(secmaxn,minn),l2=lca(secminn,maxn);
        if(lv[l1]>=lv[l2])
            printf("%d %d\n",maxn,lv[l1]);
        else
            printf("%d %d\n",minn,lv[l2]);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值