codeforces1062E. Company(dfs序+LCA)

E. Company

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

The company XX has nn employees numbered from 11 through nn. Each employee uu has a direct boss pupu (1≤pu≤n1≤pu≤n), except for the employee 11 who has no boss. It is guaranteed, that values pipi form a tree. Employee uu is said to be in charge of employee vv if uu is the direct boss of vv or there is an employee ww such that ww is in charge of vv and uu is the direct boss of ww. Also, any employee is considered to be in charge of himself.

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

  • lv(1)=0lv(1)=0
  • lv(u)=lv(pu)+1lv(u)=lv(pu)+1 for u≠1u≠1

In the near future, there are qq possible plans for the company to operate. The ii-th plan consists of two integers lili and riri, meaning that all the employees in the range [li,ri][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 uu is chosen as the project manager for the ii-th plan then for every employee v∈[li,ri]v∈[li,ri], uu must be in charge of vv. Note, that uu is not necessary in the range [li,ri][li,ri]. Also, uu is always chosen in such a way that lv(u)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 nn and qq (2≤n≤1000002≤n≤100000, 1≤q≤1000001≤q≤100000) — the number of employees and the number of plans, respectively.

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

It is guaranteed, that values pipi form a directed tree with the root of 11.

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

Output

Print qq 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

input

Copy

11 5
1 1 3 3 3 4 2 7 7 6
4 6
4 8
1 11
9 11
8 11

output

Copy

4 1
8 1
1 0
11 3
8 1

Note

In the example:

In the first query, we can choose whether 44 or 55 or 66 and the project manager will be 33.

In the second query, if we choose any employee other than the employee 88, the project manager will be 11. If we choose 88, the project manager will be 33. Since lv(3)=1>lv(1)=0lv(3)=1>lv(1)=0, choosing 88 is the best strategy.

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

In the fourth query, if we choose 99 or 1010 then the project manager will be 33. If we choose 1111 then the project manager will be 77. Since lv(7)=3>lv(3)=1lv(7)=3>lv(3)=1, we choose 1111 as the answer.

 

一、原题地址

点我传送

 

二、大致题意

给出一棵n个节点的树,有q个询问,每个询问在一段编号[ l , r ]上删除其中一个点,保证其他点的LCA所在dep最大,求删除的点和dep。

 

三、大致思路

应该删除的点是询问的段[ l , r ]dfs序上的最大或者最小的点,所以用线段树维护dfs序,然后每次询问的时候,试探把最大或最小的点删除看应该取哪个,套的是倍增的lca板子。

这样复杂度就是qlogn了吧。

 

四、代码

#include <iostream>
#include<string.h>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<map>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
const LL inf=0x3f3f3f3f;
long long  gcd(long long  a, long long  b) { return a == 0 ? b : gcd(b % a, a); }


int n,q;
const int maxn = 100005 * 4;	//线段树范围要开4倍
struct Tree
{
	int l, r, minn, maxx;
};
Tree node[maxn];		//node[maxn]为线段树处理数组
int a[maxn];			//a[maxn]为原数组
void update(int i)
{
	node[i].minn = min(node[i << 1].minn, node[(i << 1) | 1].minn);
	node[i].maxx = max(node[i << 1].maxx, node[(i << 1) | 1].maxx);
}
void build(int i, int l, int r)
{
	node[i].l = l; node[i].r = r;
	if (l == r)
	{
		node[i].minn = node[i].maxx = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(i << 1, l, mid);
	build((i << 1) | 1, mid + 1, r);
	update(i);
}
int getmin(int i, int l, int r)
{
	if (node[i].l == l&&node[i].r == r)
		return node[i].minn;
	int mid = (node[i].l + node[i].r) / 2;
	if (r <= mid) return getmin(i << 1, l, r);
	else if (l > mid) return getmin((i << 1) | 1, l, r);
	else return min(getmin(i << 1, l, mid) , getmin((i << 1) | 1, mid + 1, r));
}
int getmax(int i, int l, int r)
{
	if (node[i].l == l&&node[i].r == r)
		return node[i].maxx;
	int mid = (node[i].l + node[i].r) / 2;
	if (r <= mid) return getmax(i << 1, l, r);
	else if (l>mid) return getmax((i << 1) | 1, l, r);
	else return max(getmax(i << 1, l, mid), getmax((i << 1) | 1, mid + 1, r));
}


const int DEG = 20;
struct Edge
{
	int to, next;
} edge[maxn << 1];

int head[maxn], tot;
void addEdge(int u, int v)
{
	edge[tot].to = v;
	edge[tot].next = head[u];
	head[u] = tot++;
}

void init()
{
	tot = 0;
	memset(head, -1,sizeof(head));
}

int fa[maxn][DEG], dep[maxn];

void BFS(int root)
{
	queue<int> que;
	dep[root] = 0;
	fa[root][0] = root;
	que.push(root);
	while (!que.empty())
	{
		int tmp = que.front();
		que.pop();
		for (int i = 1; i < DEG; i++) fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
		for (int i = head[tmp]; i != -1; i = edge[i].next)
		{
			int v = edge[i].to;
			//cout << v << endl;
			if (v == fa[tmp][0]) continue;
			dep[v] = dep[tmp] + 1;
			fa[v][0] = tmp;
			que.push(v);
		}
	}
}

int LCA(int u, int v)
{
	if (dep[u] > dep[v]) swap(u, v);
	int hu = dep[u], hv = dep[v];
	int tu = u, tv = v;
	for (int det = hv - hu, i = 0; det; det >>= 1, i++)
	{
		if (det & 1)
			tv = fa[tv][i];
	}
	if (tu == tv) return tu;
	for (int i = DEG - 1; i >= 0; i--)
	{
		if (fa[tu][i] == fa[tv][i])
		{
			continue;
		}
		tu = fa[tu][i];
		tv = fa[tv][i];
	}
	return fa[tu][0];
}

int dis(int a, int b)
{
	int f = LCA(a, b);
	return dep[a] + dep[b] - 2 * dep[f];
}

int no;
int dfs_to_id[maxn];
void DFS(int nx,int pre)
{
    a[nx]=no++;
    dfs_to_id[a[nx]]=nx;
    for(int i=head[nx];i!=-1;i=edge[i].next)
    {
        int to =edge[i].to;
        if(to!=pre)
        {
            DFS(to,nx);
        }
    }
    return ;
}

int main()
{
    init();
    scanf("%d %d",&n,&q);
    for(int i=2;i<=n;i++)
    {
        int u;
        scanf("%d",&u);
        addEdge(u,i);
    }
    no=1;
    DFS(1,-1);
    build(1,1,n);
    BFS(1);
    while(q--)
    {
        int ql,qr;
        scanf("%d %d",&ql,&qr);
        int mindfs=getmin(1,ql,qr);
        int maxdfs=getmax(1,ql,qr);
        int minid=dfs_to_id[mindfs];    //求最小
        int maxid=dfs_to_id[maxdfs];    //求最大

        int cimindfs;
        if(minid==ql) cimindfs=getmin(1,ql+1,qr);
        else if(minid==qr) cimindfs=getmin(1,ql,qr-1);
        else cimindfs=min(getmin(1,ql,minid-1),getmin(1,minid+1,qr));
        int ciminid=dfs_to_id[cimindfs];
        //求次小

        int cimaxdfs;
        if(maxid==ql) cimaxdfs=getmax(1,ql+1,qr);
        else if(maxid==qr) cimaxdfs=getmax(1,ql,qr-1);
        else cimaxdfs=max(getmax(1,ql,maxid-1),getmax(1,maxid+1,qr));
        int cimaxid=dfs_to_id[cimaxdfs];
        //求次大

        int lc1=LCA(maxid,ciminid);
        int lc2=LCA(cimaxid,minid);
        if(dep[lc1]>=dep[lc2])
            printf("%d %d\n",minid,dep[lc1]);
        else
            printf("%d %d\n",maxid,dep[lc2]);


    }

    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值