題解 猴猴喫蘋果
題目描述
具體做法與心路歷程
比較簡單吧。題目要求我們每次找最長的鏈走,然後刪去點權。
以爲根,我們發現如下性質:
- 走的路徑一定是葉子節點
- 每個點走後就沒有貢獻了
我們把一顆樹畫出來,觀察即可發現,這就是長鏈剖分!!!
我們把鏈的長度賦給葉子節點,然後排序即可。
注意排序的比較!!!
/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年10月30日 星期三 14時40分57秒
*******************************/
#include<cstdio>
#include<algorithm>
using namespace std;
struct IO{
template<typename T>
IO & operator>>(T&res)
{
T q=1;char ch;
while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q;
res=(ch^48);
while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48);
res*=q;
return *this;
}
}cin;
struct edge{
int to,next;
edge(int a=0,int b=0):to(a),next(b){}
};
const int maxn=5e4+10;
int n,rt,len[maxn],son[maxn],p[maxn],head[maxn],cnt,dis[maxn],stk[maxn],_top;
edge e[maxn<<1];
void add(int u,int v)
{
e[++cnt]=edge(v,head[u]);
head[u]=cnt;
}
void dfs(int now,int fa)
{
len[now]=1;
for(int i=head[now];i;i=e[i].next)
if(e[i].to!=fa)
{
dfs(e[i].to,now);
if(len[son[now]]<len[e[i].to] || (len[son[now]]==len[e[i].to] && p[e[i].to]<p[son[now]]))
son[now]=e[i].to;
}
if(!son[now])
{
stk[++_top]=now;
p[now]=now;
}
else
p[now]=p[son[now]];
len[now]=len[son[now]]+1;
}
void dfs(int now,int res,int fa)
{
if(!son[now])
{
dis[now]=res;
return;
}
else
dfs(son[now],res+1,now);
for(int i=head[now];i;i=e[i].next)
if(e[i].to!=fa && e[i].to!=son[now])
dfs(e[i].to,1,now);
}
bool cmp(int a,int b)
{
if(dis[a]==dis[b]) return a<b;
return dis[a]>dis[b];
}
int main()
{
//freopen("apple.in","r",stdin);
//freopen("apple.out","w",stdout);
cin>>n>>rt;
int u;
rt++;
for(int i=2;i<=n;i++)
{
cin>>u; u++;
add(u,i);
add(i,u);
}
dfs(rt,0);
dfs(rt,1,0);
sort(stk+1,stk+_top+1,cmp);
printf("%d\n",rt-1);
for(int i=1;i<=_top;i++)
printf("%d\n",stk[i]-1);
return 0;
}
//14:55