1. 程式人生 > >CF1065F Up and Down the Tree

CF1065F Up and Down the Tree

www. down namespace 單獨 意思 超過 回來 題意 names

題意:給你一棵樹,你起點在1,1也是根節點,你每次可以選擇去你子樹的某個葉子節點,也可以選擇,從葉子節點返回距離不超過k的一個根,也就是說,你從1開始,向下跳,選擇一個葉子(就是沒有子樹的節點),然後可以選擇一個距離小於等於k的點跳回去,然後繼續跳下去再跳上來,問你最多能去多少個葉子節點,n<=1e6

題解

大概的意思就是樹形dp,$h[u]$表示$u$點到最近的葉子結點的距離,$dp[u]$表示$u$點最多能到的葉子的數量,$a[u]$表示從$u$跳下去又能跳回來的最多的點數

然後大概的思路就是從下往上考慮,先把子樹裏跳了能回來的節點全都跳一遍,然後再跳下去永遠不回來

然後似乎是$h[u]>=k$的時候把$a[u]$設為$0$,因為它對父親已經不會有貢獻了

我的理解的話,就是把子樹裏所有跳下去能回來的節點單獨記錄,然後判斷一下跳下去就回不來的方法哪一個更優,然後能回來的跳完之後就跳下去永遠不會來就好了

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 5 char buf[1<<21],*p1=buf,*p2=buf;
 6 template<class
T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 8 inline int read(){ 9 #define num ch-‘0‘ 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch==-)&&(flag=true
); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 const int N=1e6+5,inf=0x3f3f3f3f; 19 int head[N],Next[N],ver[N],tot; 20 inline void add(int u,int v){ 21 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 22 } 23 int dp[N],a[N],h[N],n,k; 24 void dfs(int u){ 25 h[u]=inf; 26 for(int i=head[u];i;i=Next[i]){ 27 int v=ver[i];dfs(v); 28 cmin(h[u],h[v]+1),a[u]+=a[v],cmax(dp[u],dp[v]-a[v]); 29 } 30 dp[u]+=a[u]; 31 if(h[u]==inf) dp[u]=a[u]=1,h[u]=0; 32 if(h[u]>=k) a[u]=0; 33 } 34 int main(){ 35 // freopen("testdata.in","r",stdin); 36 n=read(),k=read(); 37 for(int i=2,fa;i<=n;++i) 38 fa=read(),add(fa,i); 39 dfs(1); 40 printf("%d\n",dp[1]); 41 return 0; 42 }

CF1065F Up and Down the Tree