链接:https://ac.nowcoder.com/acm/contest/5669/A
来源:牛客网

题目描述
As a member of Coffee Chicken, ZYB is a boy with excellent data structure skills.

Consider the following problem: Give a rooted tree with N {N} N vertices. Vertices are numbered from 1 {1} 1 to N {N} N, and the root is always vertex 1 {1} 1. You are allowed to assign at most K {K} K key vertices so that the maximum ancient distances among all vertices is as small as possible. Denote the ancient distance of vertex x {x} x as: The distance between x {x} x and the first key vertex on the path from x {x} x to the root. For example, if the tree is 1 − 2 − 3 1-2-3 1−2−3 and the set of key vertices is { 2 } {\{2\}} {2}, then the ancient distances of all vertices are { + ∞ , 0 , 1 } \{+\infty,0,1\} {+∞,0,1}.

ZYB then strengthens this problem: Please find the answer for each K ∈ { 1 , 2 , … , N } K \in \{1,2,\dots,N\} K∈{1,2,…,N}. Could you accept ZYB’s challenge?
输入描述:
The input contains multiple test cases.
For each test case, the first line contains a integer N ( 1 ≤ N ≤ 2 × 1 0 5 ) N(1 \le N \le 2 \times 10^5) N(1≤N≤2×105), indicating the number of vertices in the tree.
In the second line, there are N − 1 {N-1} N−1 integers, the i {i} i-th integer f i ( 1 ≤ f i ≤ i ) f_i(1 \le f_i \le i) fi​(1≤fi​≤i) means that there is an edge between f i f_i fi​ and i + 1 {i+1} i+1.
It’s guaranteed that there are at most 5 {5} 5 test cases with N > 1000 {N>1000} N>1000, and the sum of N {N} N over all test cases will not exceed 1.2 × 1 0 6 1.2 \times 10^6 1.2×106.
输出描述:
For each test case, you should output the sum of all answers instead of each of them.
示例1

输入
3
1 2
3
1 1
输出
3
2

说明
The answer for the first test case is { 2 , 1 , 0 } {\{2,1,0\}} {2,1,0}.
The answer for the second test case is { 1 , 1 , 0 } {\{1,1,0\}} {1,1,0}.
备注:
If you have any possible solution, try it bravely!
直接根据关键节点的数量 K K K求最小化的最大ancient distances不好求,但是如果给定最长的ancient distances求所需要的关键节点的最小数量比较容易。
具体做法是枚举最长距离 x x x,然后在树上未标记的节点中找最深的节点,为保证最深的节点的ancient distances至多为 x x x,同时根据贪心原则,深度越浅的关键节点相应子树节点越多,因此将 x x x节点向上第 x x x个祖先设为关键节点,可以保证尽可能多的节点ancient distances不大于 x x x。将该关键节点都标记一下。最后可以得到最长的ancient distances为 x x x时所需要的关键节点的最小数量。
从大到小枚举 x x x可以保证最终节点数量为 K K K时的最小距离 x x x被更新成最小。
由于每次求得的是 K K K的最小值,最后可能有一些 K K K对应的 x x x没有被更新到,这些 K K K对应的 x x x值是所有小于 K K K的对应 x x x中的最小值。
为防止重新建线段树导致复杂度退化,每次修改线段树时要记录修改的区间,以便恢复。
向上找第 x x x祖先个祖先可以通过树上倍增预处理做到每次 O ( l o g n ) O(logn) O(logn)复杂度,标记节点可以在dfs序上建线段树实现 O ( l o g n ) O(logn) O(logn)复杂度标记。最坏情况整个树是一条链,这样总共需要标记的关键节点数为 n 1 + n 2 + n 2 + ⋯ + n n = n H n \frac{n}{1}+\frac{n}{2}+\frac{n}{2}+\dots+\frac{n}{n}=nH_n 1n​+2n​+2n​+⋯+nn​=nHn​。每次标记关键节点时倍增和线段树复杂度为 O ( l o g n ) O(logn) O(logn)。因此总体时间复杂度为 O ( n H n l o g n ) O(nH_nlogn) O(nHn​logn)。

#include <bits/stdc++.h>#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector<int>
#define pii pair<int,int>
#define mii unordered_map<int,int>
#define msi unordered_map<string,int>
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<<x<<endl
using namespace std;inline int qr() {int f = 0, fu = 1;char c = getchar();while (c < '0' || c > '9') {if (c == '-')fu = -1;c = getchar();}while (c >= '0' && c <= '9') {f = (f << 3) + (f << 1) + c - 48;c = getchar();}return f * fu;
}const int N = 2e5 + 10;
int head[N], ver[N << 1], Next[N << 1], tot;
int id[N], L[N], R[N], num;
int f[N][20], d[N], ans[N];
int n, t;
vi tmp;struct Seg_Tree {struct {int l, r, x, d;} t[N * 4], tmp[N * 4];void build(int p, int l, int r) {t[p].l = l, t[p].r = r;if (l == r) {t[p].d = d[id[l]], t[p].x = id[l], tmp[p] = t[p];return;}int mid = (l + r) >> 1;build(p << 1, l, mid);build(p << 1 | 1, mid + 1, r);if (t[p << 1].d >= t[p << 1 | 1].d)t[p].d = t[p << 1].d, t[p].x = t[p << 1].x;elset[p].d = t[p << 1 | 1].d, t[p].x = t[p << 1 | 1].x;tmp[p] = t[p];}void change(int p, int l, int r, int op) {if (op == -1 && t[p].d == -1)return;if (l <= t[p].l && r >= t[p].r) {if (op == -1)t[p].d = -1;else t[p] = tmp[p];return;}int mid = (t[p].l + t[p].r) >> 1;if (l <= mid)change(p << 1, l, r, op);if (r > mid) change(p << 1 | 1, l, r, op);if (op == -1) {if (t[p << 1].d >= t[p << 1 | 1].d)t[p].d = t[p << 1].d, t[p].x = t[p << 1].x;else t[p].d = t[p << 1 | 1].d, t[p].x = t[p << 1 | 1].x;} else t[p] = tmp[p];}
} tr;inline void add(int x, int y) {ver[++tot] = y;Next[tot] = head[x];head[x] = tot;
}inline void init() {t = log2(n), tot = 0, num = 0, d[1] = 1;repi(i, 1, n)head[i] = 0, ans[i] = INF;
}void dfs(int x, int fa) {id[++num] = x, L[x] = num;reps(x) {int y = ver[i];if (y == fa)continue;f[y][0] = x, d[y] = d[x] + 1;repi(j, 1, t)f[y][j] = f[f[y][j - 1]][j - 1];dfs(y, x);}R[x] = num;
}inline int find(int x, int u) {int e = log2(u);repi(i, 0, e)if ((u >> i) & 1)x = f[x][i];return max(1, x);
}inline int solve(int x) {tmp.clear();while (tr.t[1].d != -1) {int fa = find(tr.t[1].x, x);tmp.pb(fa);tr.change(1, L[fa], R[fa], -1);}for (auto it:tmp)tr.change(1, L[it], R[it], 1);return tmp.size();
}int main() {while (scanf("%d", &n) != EOF) {init();repi(i, 2, n) {int x = qr();add(i, x), add(x, i);}dfs(1, 0);tr.build(1, 1, n);repd(i, n - 1, 0) ans[solve(i)] = i;ll sum = 0;repi(i, 2, n)ans[i] = min(ans[i], ans[i - 1]);repi(i, 1, n)sum += ans[i];pl(sum);}return 0;
}

Ancient Distance相关推荐

  1. Ancient Distance(妙啊!!!) [2020牛客暑期多校训练营(第四场)]

    Ancient Distance 给定一颗根为111有nnn个节点的树,每次可以选定树上kkk节点当作特殊节点, 定义dis(u)dis(u)dis(u)为,从u−>1u->1u−> ...

  2. 牛客多校4 - Ancient Distance(树上倍增+dfs序+线段树)

    题目链接:点击查看 题目大意:给出一棵 n 个节点且以点 1 为根节点的的树,现在给出一个 k ,需要在树上选择 k 个关键点,使得 n 个点到达根节点的路径上,出现的最近的关键点的距离的最大值最小, ...

  3. 2020牛客暑期多校训练营(第四场)

    2020牛客暑期多校训练营(第四场) 这场属实有点难受 文章目录 A Ancient Distance B Basic Gcd Problem 题目 代码: C Count New String D ...

  4. 2018 Google kickstart Problem A. Planet Distance

    题目描述 Small dataset 3 ≤ N ≤ 30. Large dataset 3 ≤ N ≤ 1000.input 2 5 1 2 2 3 3 4 2 4 5 3 3 1 2 3 2 1 ...

  5. 字符串编辑距离(Edit Distance)

    一.问题描述 定义 字符串编辑距离(Edit Distance),是俄罗斯科学家 Vladimir Levenshtein 在 1965 年提出的概念,又称 Levenshtein 距离,是指两个字符 ...

  6. Levenshtein distance 编辑距离算法

    这几天再看 virtrual-dom,关于两个列表的对比,讲到了 Levenshtein distance 距离,周末抽空做一下总结. Levenshtein Distance 介绍 在信息理论和计算 ...

  7. 【leetcode】1030. Matrix Cells in Distance Order

    题目如下: We are given a matrix with R rows and C columns has cells with integer coordinates (r, c), whe ...

  8. leetcode Edit Distance

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4051082.html 题目链接:leetcode Edit Distance 最短编辑距离, ...

  9. 解题报告(一)F、(2018 ACM - ICPC shenyang I)Distance Between Sweethearts(数学期望 + 乘法原理 + FWT)(4.5)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

最新文章

  1. str_pad函数php,str_pad
  2. python xlsxwriter 画图_Python XlsxWriter模块Chart类用法实例分析
  3. Netiler annotation 用法
  4. python循环语句打印矩形_Python中使用循环语句打印三角形、菱形
  5. oracle 触发器登录,【学习笔记】Oracle触发器 实现指定用户登录oracle案例
  6. 字典-字典的循环遍历
  7. ajax方式表单拦截
  8. CMake的简单使用
  9. 理解:回归与拟合、归一化与标准化
  10. MSYS2 的安装与使用
  11. python三维矩阵_python三维矩阵
  12. go 变量与json相互转换
  13. 多个圆通快递单号的物流信息如何在电脑上批量查询?
  14. 如何将一个vector内容赋值给另一个vector C/C++
  15. “数智话”技术沙龙 第四期 | 弹性MapReduce(EMR)专场内容回顾!
  16. Tomcat 启动闪退问题
  17. 下一代存储技术面临市场窗口期?
  18. switzerland, we're coming
  19. 强到离谱!阿里P8前端面试全套笔记,即将删除~
  20. OGC 网络数据服务的类型与操作+实现GeoServer软件在Apache+Tomcat的部署+OGC数据服务WMS、WFS和WCS的发布

热门文章

  1. 马哥Linux学习笔记8-4lvm应用
  2. 降维打击!北大「韦神」一夜拿下困住6名博士4个月的难题
  3. jav1.8 Stream详解
  4. 昆山农商行用户画像——DataExplore
  5. java_百度_面试
  6. 织梦dedecm v5.7 flink 友情链接
  7. 学习游戏建模是自学还是培训哪个靠谱?
  8. 使用Kotlin在Android Studio中创建井字游戏
  9. 电脑通过手机(摩托E2)上网
  10. PPT修复文档内容方法之一