辣鸡题解
题目描述
给出一棵树,可以任意选择一个点作为起始点(消耗1时间)。在1单位时间内,每个上轮已访问过的点可以扩展一个节点,求最少花费时间和最少花费的起点。
20%
DP
。设
F[i]
表示传完
i
为根的子树所需要的最小时间。
则
解释一下。
如果i有一些儿子要传,那么肯定先传该从儿子传下去时间大的,否则以后再传所需时间更长。
然后每个点都做一遍就可以20分了。
(25分?玄学)
话说我考试时要是交上去就有25分了
80% & 100%
官方的题解是说把一个点从作为根的父亲上移过去,使其成为新的根。
中途似乎要用到RMQ+二分之类的奇♂妙算法所以果断弃疗
咳咳
讲讲个人的奇♂妙算法。
20%的算法瓶颈在于要把每个点都算一遍,所以时间复杂度是
O(N2logn)
设
G[i]
表示假设以i为根的情况下,传遍i的父亲所在子树所需要的最小时间
似乎不易理解实际比题解好理解多了
至于
G[i]
的转移也很显然
每次从i的兄弟的F,还有i父亲的G中转移,具体类似F[i]的转移方式。
这样随便水一下能有80分
100分类似80分,只不过有些人工数据十分鬼畜,基本上是一个点连着剩下一片点,这样效率会退化到 O(n2logn)
然而解决方法也很简单,只需要从父亲直接推到儿子就行了。
因为一个父亲的儿子中只有一条边会改变,所以把转移的信息记录下来排序,根据每个儿子分别计算答案。
把一个边删掉后,在这条边之前(从大到小排序)的值不变,之后的会-1
问为什么的去看F的转移方程。
这里就不细说了因为太水
code
#include <iostream>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std;
int n,i,j,k,l,m2;
int a[200001][3];
int ls[200001];
int fa[200001];
int f[200001];
int g[200001];
int b[200002][2];
int m[200002];
int ans[200001];
int max(int x,int y) {return (x>y?x:y);}
int min(int x,int y) {return (x<y?x:y);}
void qsort(int l,int r)
{
int i,j,k,mid;
i=l;
j=r;
mid=b[(l+r)/2][0];
while (i<=j)
{
while (b[i][0]>mid) i++;
while (b[j][0]<mid) j--;
if (i<=j)
{
k=b[i][0];
b[i][0]=b[j][0];
b[j][0]=k;
k=b[i][1];
b[i][1]=b[j][1];
b[j][1]=k;
i++;
j--;
}
}
if (l<j)
qsort(l,j);
if (i<r)
qsort(i,r);
return;
}
void dfs(int t)
{
int i,j;
f[t]=0;
j=0;
for (i=ls[t]; i; i=a[i][2])
dfs(a[i][1]);
for (i=ls[t]; i; i=a[i][2])
b[++j][0]=f[a[i][1]];
qsort(1,j);
fo(i,1,j)
f[t]=max(f[t],b[i][0]+i);
return;
}
void dfs2(int t)
{
int i,j;
m2=0;
j=0;
for (i=ls[t]; i; i=a[i][2])
b[++j][0]=f[a[i][1]],b[j][1]=a[i][1];
if (fa[t])
b[++j][0]=g[t],b[j][1]=0;
qsort(1,j);
fd(i,j,1)
m[i]=max(m[i+1],b[i][0]+i);
fo(i,1,j)
{
if (b[i][1])
g[b[i][1]]=max(m2,m[i+1]-1);
m2=max(m2,b[i][0]+i);
}
fo(i,1,j)
m[i]=0;
for (i=ls[t]; i; i=a[i][2])
if (ls[a[i][1]])
dfs2(a[i][1]);
return;
}
int main()
{
freopen("news.in","r",stdin);
freopen("news.out","w",stdout);
scanf("%d",&n);
fo(i,1,n-1)
{
scanf("%d",&fa[i+1]);
a[i][0]=fa[i+1];
a[i][1]=i+1;
a[i][2]=ls[a[i][0]];
ls[a[i][0]]=i;
}
dfs(1);
g[1]=0;
dfs2(1);
j=23333333;
fo(i,1,n)
{
k=0;
if (fa[i])
b[++k][0]=g[i];
for (l=ls[i]; l; l=a[l][2])
b[++k][0]=f[a[l][1]];
qsort(1,k);
fo(l,1,k)
ans[i]=max(ans[i],b[l][0]+l);
ans[i]++;
j=min(j,ans[i]);
}
printf("%d\n",j);
fo(i,1,n)
if (ans[i]==j)
printf("%d ",i);
printf("\n");
fclose(stdin);
fclose(stdout);
return 0;
}