猴猴最喜歡在樹上玩耍,一天猴猴又跳上了一棵樹,這棵樹有N個蘋果,每個蘋果有一個編號,分別爲0~N-1,它們之間由N-1個樹枝相連,猴猴可以從樹枝的一端爬到樹枝的另一端,所以猴猴可以從任意一個蘋果的位置出發爬到任意猴猴想去的蘋果的位置。猴猴開始在編號爲K的蘋果的位置,並且把這個蘋果吃了,之後每一天猴猴都要去喫一個蘋果,但是樹上那麼多蘋果喫哪個呢?猴猴想到自己去喫蘋果時一定會把路上遇到的蘋果都喫掉,於是猴猴決定去喫能讓自己這天喫的蘋果數量最多的那個蘋果,如果有多個蘋果滿足條件,猴猴就會去喫這些中編號最小的蘋果,那麼猴猴會按照什麼順序喫蘋果呢?
輸入
第一行兩個數N和K。(N<=50000)
第2-N行,第i+1行的數字Ai表示i和Ai之間有一根樹枝相連。
輸出
每行一個數字,依次表示猴猴所在的位置
數據範圍
對於30%的數據:N<=100
對於60%的數據:N<=1000
對於100%的數據:N<=50000,0<=K<N
輸入樣例
輸入樣例1
7 2
0
1
2
2
1
4
輸入樣例2
8 1
0
0
1
3
0
3
1
輸入樣例3
4 2
0
0
1
輸出樣例
輸出樣例1
2
0
6
3
5
輸出樣例2
1
2
4
5
6
7
輸出樣例3
2
3
樣例解釋
第一天最多可以喫到兩個蘋果,可以去0或6,去0
第二天最多喫兩個,去6
第三天最多喫一個,去3
第四天最多喫一個,去5
//written by zzy
題目大意:
有一個樹,每個點開始有個蘋果,猴子會從一個點開始找一條有最多蘋果的路,然後喫掉那一條路上的所有的蘋果,求猴子喫那條路上最後蘋果的順序。
題解 :
首先不難想到猴子每次必到葉子結點,
將起始點看成根,
可以看成猴子每喫完一次後重回到根節點(因爲路徑上的蘋果喫完了後沒有貢獻),
再遍歷一次,求出每個點的深度和父親,按深度把葉子結點從大到小排序,
然後可以倒過來想,讓每個葉子結點往上跳,遇到跳過的點就停,記錄跳的次數(即爲從根喫到它的貢獻值),
再按此值排序即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 50005
using namespace std;
int l,i,j,n,m,k,num,v;
int cnt[N],fa[N],d[N];
bool b[N],vis[N];
int next[2*N],list[2*N],y[2*N];
struct leafs {
int a,x,s;
}leaf[N];
void add(int x)
{
next[++l]=list[x];
list[x]=l;
}
bool cmp_x(leafs p,leafs q) {
return (p.x>q.x)||(p.x==q.x&&p.a<q.a);
}
bool cmp_s(leafs p,leafs q) {
return (p.s>q.s)||(p.s==q.s&&p.a<q.a);
}
void dfs(int father,int x)
{
for (int t=list[x],to=y[t];t;t=next[t],to=y[t])
if (b[to]) {
b[to]=false; fa[to]=x; d[to]=d[x]+1;
if (cnt[x]!=1) dfs(x,to);
}
}
int main()
{
scanf("%d%d",&n,&k);
printf("%d\n",k);
for (i=1;i<=n-1;i++) {
scanf("%d",&v);
y[i*2-1]=v; add(i);
y[i*2]=i; add(v);
cnt[i]++; cnt[v]++;
}
memset(b,true,sizeof(b));
b[k]=false; d[k]=0; cnt[k]=0;
dfs(-1,k);
for (i=0;i<=n-1;i++)
if (cnt[i]==1)
leaf[++num].a=i,leaf[num].x=d[i];
sort(leaf+1,leaf+num+1,cmp_x);
vis[k]=true;
for (i=1;i<=num;i++) {
int now=leaf[i].a;
while (!vis[now])
vis[now]=true,leaf[i].s++,now=fa[now];
}
sort(leaf+1,leaf+num+1,cmp_s);
for (i=1;i<=num;i++)
printf("%d\n",leaf[i].a);
}