CF1039D You Are Given a Tree


題目傳送門

題目大意

給出一棵$ n $個節點的樹,對於$ 1 $~$ n $間的每一個數$ k $,你需要求出: 最多能選出多少條互不相交的路徑,使得每條路徑的長度都為$ k $。

思路

首先思考暴力的做法。就是貪心+樹形dp,把整個樹$ dfs $一次,對於每個節點考慮它子節點的最長鏈和次長鏈。如果最長鏈+次長鏈+$ 1 \geq k $,那么就說明它子節點的最長鏈和次長鏈通過那個子節點連起來形成的鏈可以滿足長度大於等於$ k $,答案+$ 1 $。

那么為什么滿足條件就一定要先把它們連起來呢?因為由於當前存在了一條滿足要求的鏈,如果不計入答案,把最長鏈往上傳,那么最多對答案也只有$ 1 $的貢獻。所以先連起來可能會更優。這樣時間復雜度就是$ O(n^2) $。

之后就用分治優化。設分治節點為t,對於第一段直接用暴力求解,時間復雜度就是$ O(nt) $,對於第二段,因為答案只會在$ 0 $~$ \frac{n}{t} $這個范圍內,而且是單調不升的,相同答案的k值肯定是連在一起的,所以可以考慮從左往右掃一遍,每次用二分出答案相同的一段,這樣時間最多也就$ \frac{n^2\log(n)}{t} $ 。所以當t取$ \sqrt[]{n\log(n)} $時,時間復雜度最小,為$ O(n\sqrt[]{n\log(n)}) $。

當然,$ t $取$ \sqrt n $會更容易理解,雖然時間沒有$ t $=$ \frac{n^2\log(n)}{t} $ 快,但只要我們優化一下,去掉$ dfs $的過程,記錄$ dfs $序,通過$ for $循環以達到$ dfs $的目的,也是可以過的。

所以我也把這個小優化也加到了我的代碼里。

代碼

#include<bits/stdc++.h>
using namespace std;
int n,q,x,y,head[200002],Fa[100001],dfsx[100001],f[100001],cnt=0,tot=0,t,l,r,mid;
struct node{
    int nxt,to;
}e[200002];
void add(int x,int y){
    e[++cnt].nxt=head[x];
    e[cnt].to=y;
    head[x]=cnt;
}
void dfs(int x,int fa){
    Fa[x]=fa;
    for(int i=head[x];i;i=e[i].nxt){
        int v=e[i].to;
        if(v!=fa) dfs(v,x);
    }
    dfsx[++tot]=x;
    return;
}
int solve(int x){
    int k,ans=0;
    for(int i=1;i<=n;i++) f[i]=1;
    for(int i=1;i<=n;i++){
        int k=dfsx[i];
        if(Fa[k]&&~f[Fa[k]]&&~f[k]){
            if(f[k]+f[Fa[k]]>=x){
                f[Fa[k]]=-1;
                ans++;
            }
            else f[Fa[k]]=max(f[Fa[k]],f[k]+1);
        }
    }
    return ans;
}
int main(){
    scanf("%d",&n);
    q=sqrt(n*log(n)/log(2));
    for(int i=1;i<n;i++){
        scanf("%d %d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    printf("%d\n",n);
    for(int i=2;i<=q;i++) printf("%d\n",solve(i));
    for(int i=q+1;i<=n;i=l+1){
        l=i;
        r=n;
        t=solve(i);
        while(l<r){
            mid=(l+r+1)>>1;
            if(solve(mid)==t) l=mid;
            else r=mid-1;
        }
        for(int j=i;j<=l;j++) printf("%d\n",t);
    }
    return 0;
}
請不要隨意抄代碼!

 

不要忘記點個贊哦

 

完結撒花

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM