Codeforces 1039D You Are Given a Tree [根号分治,整体二分,贪心]

洛谷

Codeforces


根号分治真是妙啊。


思路

考虑对于单独的一个\(k\)如何计算答案。

与“赛道修建”非常相似,但那题要求边,这题要求点,所以更加简单。

在每一个点贪心地把子树升上来的两条最长的链拼在一起,能组就组,否则把最长链往上送,复杂度\(O(n)\)

那么多个\(k\)怎么办呢?

分析一波,\(k<\sqrt{n}\)时可以暴力计算,而\(k>\sqrt{n}\)\(ans_k\leq \lfloor \frac{n}{k}\rfloor\),只有\(\sqrt{n}​\)种取值。

显然\(ans\)单调不增,所以可以二分边界,复杂度\(O(n\sqrt{n}\log n)\)

把界限调为\(\sqrt{n\log n}\)后复杂度可以优化至\(O(n\sqrt{n\log n})\)

然而我这么写T掉了……

发现网上还有一种整体二分的写法,不知为何跑的飞快……只能改成整体二分了……


代码

注释掉的是根号分治的代码,求找错\(Q\omega Q\)

#include<bits/stdc++.h>
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define sz 101010
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    template<typename T>inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    template<typename T>inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.txt","r",stdin);
        #endif
    }
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n;
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t)
{
    edge[++ecnt]=(hh){t,head[f]};
    head[f]=ecnt;
    edge[++ecnt]=(hh){f,head[t]};
    head[t]=ecnt;
}

int K;
int f[sz];
int id[sz],fa[sz],cnt;
#define v edge[i].t
void dfs(int x,int fa)
{
    ::fa[x]=fa;
    go(x) if (v!=fa) dfs(v,x);
    id[++cnt]=x;
}
int check(int len)
{
    K=len;
    int ret=0;
    rep(i,1,n)
    {
        int x=id[i],mx1=0,mx2=0;
        go(x) if (v!=fa[x])
        {
            if (f[v]>mx1) mx2=mx1,mx1=f[v];
            else if (f[v]>mx2) mx2=f[v];
        }
        if (mx1+mx2+1>=K) ++ret,f[x]=0;
        else f[x]=mx1+1;
    }
    return ret;
}
#undef v

int ans[sz];

void solve(int l,int r,int L,int R)
{
    if (r<l) return;
    if (L==R) { rep(i,l,r) ans[i]=L; return; }
    int mid=(l+r)>>1,s=check(mid);
    ans[mid]=s;
    solve(l,mid-1,s,R),solve(mid+1,r,L,s);
}

int main()
{
    file();
    read(n);
    int x,y;
    rep(i,1,n-1) read(x,y),make_edge(x,y);
    dfs(1,0);
    /*
    int T=sqrt(n*log2(n));
    rep(i,1,T) ans[i]=check(i);
    int las=T;
    drep(i,n/T,0)
    {
        int l=las+1,r=n,R=-1;
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if (check(mid)>=i) R=mid,l=mid+1;
            else r=mid-1;
        }
        rep(j,las+1,R) ans[j]=i;
        las=max(las,R);
    }
    rep(i,1,n) printf("%d\n",ans[i]);
    */
    solve(1,n,0,n);
    rep(i,1,n) printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/p-b-p-b/p/10365913.html