[CF1039D]You Are Given a Tree

Description:

a.png

Solution:

\(O(n^2)\) 的作法就是每次 dfs 整棵樹 貪心從下往上選,具體而言就是維護以 u 兒子傳上來的最長鏈和次長鏈,若是最長鏈 + 次長鏈 + 1 \(\geq\) \(k\) 則拼成一條長度爲 \(k\) 的鏈,而後穿一條長度爲 0 的上去,不然把最長鏈傳上去。ios

正確性:因爲當前存在最長鏈 + 次長鏈 +1\(\geq\) \(k\),就算傳一條最長鏈上去也只可能使答案增長1,而不如如今就讓最長鏈匹配了次長鏈產生1的貢獻,可能會更優。git

發現當\(k\geq \sqrt n\)時,答案 \(\le \sqrt n\),並且不難發現答案隨着k變大變小,而且由一些連續段拼接而成,咱們對於每一個答案二分其最右邊的端點使得這一塊的答案同樣,因此總時間複雜度爲 \(O(n\sqrt n\log n)\)spa

這題比較卡常,不能寫遞歸的 dfs,把每一個點的 dfn 序搞出來就能夠用 for 循環實現了。code

Code:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <fstream>

using namespace std;

#define LL long long
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define MP(x, y) std::make_pair(x, y)
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define REP(i, a, b) for (register int (i) = (a); (i) <= (b); ++(i))
#define GO cerr << "GO" << endl;

inline void proc_status()
{
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
}
template<class T> inline T read() 
{
    register char c;
    register T x(0), f(1);
    while (!isdigit(c = getchar())) if (c == '-') f = -1;
    while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
    return x * f;
}
template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }

const int maxN = (int) 1e5;

int n;
int ans[maxN + 2],ver[maxN<<1],nxt[maxN<<1],head[maxN+2],tot,dfst,rev[maxN+2];
int first[maxN+2],second[maxN+2],fa[maxN+2];

void link(int u, int v)
{ ver[++tot]=v,nxt[tot]=head[u],head[u]=tot; }

void Input()
{
    n = read<int>();
    for (int i = 1; i < n; ++i)
    {
        int u = read<int>(), v = read<int>();
        link(u, v), link(v, u);
    }
}

void dfs(int u, int f)
{
    rev[++dfst]=u;
    fa[u]=f;
    for (int i = head[u];i;i=nxt[i])
    {
        int v=ver[i];
        if(v==f)continue;
        dfs(v,u);
    }
}

inline int Calc(int l)
{
    memset(first,0,4*(n+1));
    memset(second,0,4*(n+1));
    int res(0);
    for (register int i = n; i >= 1; --i)
    {
        int u=rev[i],f=fa[u],len;
        if(first[u]+second[u]+1>=l) ++res,len=0;
        else len=first[u]+1;
        if (!f) continue;
        if(first[f] < len)second[f]=first[f],first[f]=len;
        else if(second[f]<len)second[f]=len;
    }
    return res;
}

void Solve()
{
    int i;
    int sqr = int(sqrt(n));

    dfs(1,0);
    for (i = 1; i <= sqr; ++i) ans[i] = Calc(i);
    for (; i <= n; ++i)
    {
        ans[i]=Calc(i);
        int l=i,r=n,pos=i,mid;
        while (l<=r)
        {
            mid=(l+r)>>1;
            if(Calc(mid)==ans[i])pos=mid,l=mid+1;
            else r=mid-1;
        }
        for(int j=i+1;j<=pos;++j)ans[j]=ans[i];
        i=pos;
    }
    for(int i=1;i<=n;++i)
        printf("%d\n",ans[i]);
}

int main() 
{ 
    Input();
    Solve();
    return 0;
}
相關文章
相關標籤/搜索