CodeForces 1062E Company
Description
The company \(X\) has \(n\) employees numbered from \(1\) through \(n\). Each employee \(u\) has a direct boss \(p_u\) \((1 \le p_u \le n)\), except for the employee \(1\) who has no boss. It is guaranteed, that values \(p_i\) 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(p_u)+1\) for \(u \neq 1\)
In the near future, there are \(q\) possible plans for the company to operate. The \(i\)-th plan consists of two integers \(l_i\) and \(r_i\), meaning that all the employees in the range \([l_i,r_i]\), 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 \in [l_i,r_i]\), \(u\) must be in charge of \(v\). Note, that \(u\) is not necessary in the range \([l_i,r_i]\). 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 \le n \le 100000, 1 \le q \le 100000)\) — the number of employees and the number of plans, respectively.
The second line contains \(n−1\) integers \(p_2,p_3,…,p_n(1≤p_i≤n)\) meaning \(p_{i}\) is the direct boss of employee \(i\).
It is guaranteed, that values \(p_{i}\) form a directed tree with the root of \(1\).
Each of the following \(q\) lines contains two integers \(l_i\) and \(r_i\) \((1 \le l_i < r_i \le 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
Input
11 5
1 1 3 3 3 4 2 7 7 6
4 6
4 8
1 11
9 11
8 11
Output
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 \gt 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 \gt lv(3)=1\), we choose \(11\) as the answer.
Solution
题意:给一棵树,\(n\)个点,\(q\)次询问,每次询问给定一个区间\([l, r]\),要求忽略掉\([l, r]\)中的一个点,使得剩下的$r - l $个点的LCA的深度最大,问应该忽略哪个点,忽略后的最大深度是多少。
首先求一次DFS序,对于任意点\(u\),其DFS序记为\(order[u]\)。给定区间\([l, r]\),设其中DFS序最大和最小的点分别为\(u\)和\(v\),则\(LCA[l, r]\)就是\(LCA(u, v)\)。我们可以简单证明一下,不妨设\(r = LCA(u, v)\),点\(x\)不属于以\(r\)为根的子树(记作\(SubTree(r)\))当且仅当\(order[x]\)满足以下两种情况中的一种:
- \(order[x] \lt order[r]\),即\(x\)在\(r\)之前被访问
- \(order[x] > order[i], \forall i \in SubTree(r)\),即\(x\)在\(SubTree(r)\)之后才被访问
显然,\([l, r]\)中的任何一个点都不满足上述两个条件,所以\([l, r]\)中的每个点都属于以\(r\)为根的子树,所以它们的LCA就是\(r\)。
回到我们的问题,对于每次询问,给定\([l, r]\),我们先求出其中DFS序最大、最小的点\(u, v\)以及它们的LCA \(r\)。显然,忽略\(u\)和\(v\)之外的节点对并不会改变LCA;如果忽略\(u\),那么新的LCA就是\(LCA[l, u-1]\)和\(LCA[u + 1, r]\)的LCA,我们称之为\(r_1\);同理,忽略\(v\)也可以得到一个新的LCA,我们称之为\(r_2\)。选择\(r, r_1, r_2\)中深度最大的点,我们就得到了答案。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100011;
const int maxp = 18;
vector<int> w[maxn];
int idx, dfsod[maxn], invdfsod[maxn];
int fa[maxn][maxp], dep[maxn];
void bfs(int root) {
queue<int> que;
dep[root] = 0;
fa[root][0] = root;
que.push(root);
while (!que.empty()) {
int u = que.front();
que.pop();
for (int i = 1; i < maxp; i++)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (int v : w[u]) {
if (v == fa[u][0]) continue;
dep[v] = dep[u] + 1;
fa[v][0] = u;
que.push(v);
}
}
}
int lca(int u, int v) {
if (dep[u] > dep[v])
swap(u, v);
for (int gap = dep[v] - dep[u], i = 0; gap; gap >>= 1, i++) {
if (gap & 1)
v = fa[v][i];
}
if (u == v) return u;
for (int i = maxp - 1; i >= 0; i--) {
if (fa[u][i] == fa[v][i])
continue;
u = fa[u][i], v = fa[v][i];
}
return fa[u][0];
}
void dfs(int u, int pre = -1) {
dfsod[u] = ++idx;
invdfsod[idx] = u;
for (int v : w[u]) {
if (v == pre) continue;
dfs(v, u);
}
}
struct node {
int l, r, mx, mn;
} seg[maxn << 2];
void pushup(int x) {
seg[x].mx = max(seg[x << 1].mx, seg[x << 1 | 1].mx);
seg[x].mn = min(seg[x << 1].mn, seg[x << 1 | 1].mn);
}
void build(int x, int l, int r) {
seg[x].l = l, seg[x].r = r;
if (l == r) {
seg[x].mx = seg[x].mn = dfsod[l];
return;
}
int m = (l + r) >> 1;
build(x << 1, l, m);
build(x << 1 | 1, m + 1, r);
pushup(x);
}
pair<int, int> query(int x, int l, int r) {
int L = seg[x].l, R = seg[x].r;
if (l <= L && r >= R)
return make_pair(seg[x].mn, seg[x].mx);
int m = (L + R) >> 1;
int mx = 0, mn = 1 << 30;
if (l <= m) {
auto v = query(x << 1, l, r);
mn = min(mn, v.first);
mx = max(mx, v.second);
}
if (r > m) {
auto v = query(x << 1 | 1, l, r);
mn = min(mn, v.first);
mx = max(mx, v.second);
}
return make_pair(mn, mx);
}
// 区间[l, r]的LCA
int getlca(int l, int r) {
if (l > r) return -1;
auto x = query(1, l, r);
int u = invdfsod[x.first], v = invdfsod[x.second];
return lca(u, v);
}
// 忽略u后,区间[l, r]的LCA
int getlca(int l, int r, int u) {
int a = getlca(l, u - 1), b = getlca(u + 1, r);
if (a == -1) return b;
if (b == -1) return a;
return lca(a, b);
}
int main() {
int n, q;
scanf("%d%d", &n, &q);
for (int i = 2; i <= n; ++i) {
int x; scanf("%d", &x);
w[x].push_back(i);
w[i].push_back(x);
}
bfs(1);
dfs(1);
build(1, 1, n);
dep[0] = -1;
while (q--) {
int l, r;
scanf("%d%d", &l, &r);
auto x = query(1, l, r);
int u = invdfsod[x.first], v = invdfsod[x.second];
int c = lca(u, v), a = getlca(l, r, u), b = getlca(l, r, v);
int mx = max(dep[c], max(dep[a], dep[b])), y;
if (mx == dep[c]) y = l;
else if (mx == dep[a]) y = u;
else y = v;
printf("%d %d\n", y, mx);
}
return 0;
}
CodeForces 1062E Company的更多相关文章
- Codeforces 1090A - Company Merging - [签到水题][2018-2019 Russia Open High School Programming Contest Problem A]
题目链接:https://codeforces.com/contest/1090/problem/A A conglomerate consists of n companies. To make m ...
- Codeforces 1062E 题解
给出一棵有根树,1为根结点,接下来q次询问,每次给出一个[l,r]区间,现在允许删掉[l,r]区间内任何一个点,使得所有点的最近公共祖先的深度尽可能大,问删掉的点是哪个点,深度最大是多少. 做法: 线 ...
- CodeForces 1025G Company Acquisitions
题意 描述有点麻烦,就不写了. \(\texttt{Data Range:}1\leq n\leq 500\) 题解 势能函数这个东西好神啊-- 这个题目用常规的 DP 好像做不出来,所以我们可以考虑 ...
- Codeforces 556D Restructuring Company
传送门 D. Restructuring Company time limit per test 2 seconds memory limit per test 256 megabytes input ...
- Codeforces Round #321 (Div. 2) B. Kefa and Company 二分
B. Kefa and Company Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/580/pr ...
- [刷题]Codeforces 794C - Naming Company
http://codeforces.com/contest/794/problem/C Description Oleg the client and Igor the analyst are goo ...
- CodeForces 125E MST Company
E. MST Company time limit per test 8 seconds memory limit per test 256 megabytes input standard inpu ...
- Codeforces 1062 E - Company
E - Company 思路: 首先,求出每个点的dfs序 然后求一些点的公共lca, 就是求lca(u, v), 其中u是dfs序最大的点, v是dfs序最小的大点 证明: 假设o是这些点的公共lc ...
- Codeforces Round #520 (Div. 2) E. Company(dfs序判断v是否在u的子树里+lca+线段树)
https://codeforces.com/contest/1062/problem/E 题意 给一颗树n,然后q个询问,询问编号l~r的点,假设可以删除一个点,使得他们的最近公共祖先深度最大.每次 ...
随机推荐
- UIView使用UIMotionEffect效果
UIView使用UIMotionEffect效果 这个效果在模拟器上看不了,所以无法截图. UIView+MotionEffect.h + UIView+MotionEffect.m // // ...
- 进程分析之CPU
进程分析之CPU 进程分析之CPU 本文转载自:https://github.com/ColZer/DigAndBuried/blob/master/system/cpu.md 在<进程分析之内 ...
- K8S Deployment 命令
创建 Deployment kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml --record ...
- AltiumDesigner17学习指南
AltiumDesigner工程模板 工程文件管理 视图->桌面布局->默认 恢复界面 AltiumDesigner17功能 修改元件标号 双击元件标号,在Designetor的Value ...
- ORACLE分区表操作
ORACLE分区表的操作应用 摘要:在大量业务数据处理的项目中,可以考虑使用分区表来提高应用系统的性能并方便数据管理,本文详细介绍了分区表的使用. 在大型的企业应用或企业级的数据库应用中,要处理的数据 ...
- 针对 Linux 环境下 gdb 动态调试获取的局部变量地址与直接运行程序时不一致问题的解决方案
基础的缓冲区溢出实践通常需要确定运行状态下程序中的某些局部变量的地址,如需要确定输入缓冲区的起始地址从而获得注入缓冲区中的机器指令的起始地址等.在 Linux 环境下,可通过 gdb 对程序进行动态调 ...
- 最新版本2018.1.1webstorm安装、汉化、破解教程
一.安装(下载与激活) 1.官网下载安装包https://www.jetbrains.com/webstorm/ 2.开始安装 3.选择安装目录,点击下一步 4.勾选64位,点击下一步 5.继续下一步 ...
- HBase学习之路 (八)HBase大牛博客
主要是记录一下链接 http://hbasefly.com
- zoc license code
点击导航栏上的zoc-about zoc,然后: 点击enter license: 然后输入内容即可: part A: 51698/01027/34713 part B: 00937 还有很多其他 ...
- 知乎live考研数学冲刺135+资料分享
前言 各位学弟学妹,您好,live中本来是给出了我的邮箱,通过邮箱来获取资料,但是没有想到,后来我每天打开邮箱,都是需要回复的邮件,少则一两封,多则四五封,每天如此,也是一个比较繁琐费时的方式.我决定 ...