2020牛客暑期多校训练营第四场Ancient Distance
Ancient Distance
题目描述:
作为CoffeeChickenCoffee ChickenCoffeeChicken的成员,ZYBZYBZYB是一个具有出色数据结构技能的男孩。
请考虑以下问题:给出具有N{N}N个顶点的根树。 顶点的编号从1{1}1到N{N}N,并且根始终是顶点1{1}1。 您最多可以分配K{K}K个关键顶点,以使所有顶点之间的最大“祖先距离”尽可能小。 将顶点x{x}x的“祖先距离”表示为:x{x}x与从x{x}x到根的路径上的第一个关键顶点之间的距离。 例如,如果树为111 −-− 222 −-− 333,关键顶点集为 {\{{ 2 }\}},则所有顶点的“祖先距离”为{\{{ + ∞\infty∞,000,111 }\}} ZYBZYBZYB然后加强了这个问题:请找到每个KKK ∈\in∈ {\{{ 111,222,…\dots…,NNN }\}} 的答案。 您可以接受ZYBZYBZYB的挑战吗?
输入描述:
输入包含多个测试用例。
对于每个测试用例,第一行包含一个整数NNN ((( 111 ≤\le≤ NNN ≤\le≤ 222 ×\times× 101010 5^{_5}5),表示树中的顶点数。第二行中有N−1{N-1}N−1个整数, i{i}i整数fif_ifi ((( 111 ≤\le≤ fif_ifi ≤\le≤ iii ))) 表示fif_ifi与i+1{i + 1}i+1之间存在一条边。它保证最多有N>1000{N> 1000}N>1000个测试用例,并且在所有测试用例中,N{N}N之和不会超过1.21.21.2 ×\times× 101010 6^{_6}6
输出描述:
对于每个测试用例,输出 kkk 分别为 111,222,…,nnn 时答案的和
样例输入:
3 1 2 3 1 1
样例输出:
3 2
思路:
二分答案 +++ 线段树维护
这道题一看到求最大值最小就想到二分
每次贪心查找最远的点,向上k个点放关键点,然后删左子树(注:“删除”指打标记,因为之后的计算原树还要用)直到所有的点都被删除时改变二分上下界,最后得出答案。
做法:
按顺序枚举111 ~ kkk,由于需要寻找最大值,所以用线段树维护整棵树的dfs序。
枚举k×\times×每次查找×\times×调和级数×\times×二分
总时间复杂度:OOO ((( NNN lognlog_nlogn lognlog_nlogn lognlog_nlogn )))
AC Code
#include<bits/stdc++.h> using namespace std; const int MAXN=2e6+5; int a[MAXN],dep[MAXN],d[MAXN],ans[MAXN],v[MAXN]; int n,cnt,maxn,maxm,mid; vector<int> vec[MAXN]; void dfs(int x) { d[++cnt]=x; for(int i=0;i<vec[x].size();i++) { dep[vec[x][i]]=dep[x]+1; dfs(vec[x][i]); } }//dfs序 void build(int left,int right,int l,int r) { if(left>right||l>r) return; if(l==r) { for(int i=left;i<=right;i++) ans[i]=l; return; } mid=(left+right)/2; ans[mid]=0; for(int i=1;i<=n;i++) v[i]=dep[i]; for(int i=n;i>=1;i--) { if(v[d[i]]==dep[d[i]]+mid||d[i]==1) { ans[mid]++; v[d[i]]=-1; } v[a[d[i]]]=max(v[a[d[i]]],v[d[i]]); } build(left,mid-1,ans[mid],r); build(mid+1,right,l,ans[mid]); }//二分+线段树 int main() { while(~scanf("%d",&n)) { memset(ans,0,sizeof(ans)); memset(dep,0,sizeof(dep)); dep[1]=cnt=maxn=maxm=0; for(int i=1;i<=n;i++) vec[i].clear(); for(int i=2;i<=n;i++) { scanf("%d",a+i); vec[a[i]].push_back(i); } dfs(1); for(int i=1;i<=n;i++) maxn=max(maxn,dep[i]); build(0,maxn,1,n); for(int i=1;i<=maxn;i++) maxm+=i*(ans[i-1]-ans[i]); printf("%d\n",maxm); } }
- 2020牛客暑期多校训练营(第四场)——HHarder Gcd Problem
- 2020牛客暑期多校训练营(第四场)——AAncient Distance
- 2020牛客暑期多校训练营(第四场)——I Investigating Legions
- 2020牛客暑期多校训练营第四场Operating on the Tree
- 2020牛客暑期多校训练营(第四场)
- 2020牛客暑期多校训练营(第四场)——Basic Gcd Problem
- 2020牛客暑期多校训练营第六场Binary Vector(数学,打表)
- 2020暑期牛客多校训练营第七场(J)Pointer Analysis(模拟,指针,向量)
- 2019牛客暑期多校训练营 第四场
- sequence(线段树+单调栈) (2019牛客暑期多校训练营(第四场))
- 2020牛客暑期多校训练营(第五场)
- 2020牛客暑期多校训练营第六场Grid Coloring
- 2020暑期牛客多校训练营第七场(A)Social Distancing(平面几何,动态规划,打表)
- 2019牛客暑期多校训练营(第四场)A meeting
- K number(思维和后缀以及3的特性)(2019牛客暑期多校训练营(第四场))
- 2019牛客暑期多校训练营(第四场)K number
- 2020牛客暑期多校训练营第六场K-Bag
- 2020暑期牛客多校训练营第七场(I)Valuable Forests(dp,组合数学,prufer)
- 2020牛客暑期多校训练营(第七场)
- 2020牛客暑期多校训练营(第七场)——I Valuable Forests