Codeforces Contest 1098 problem C Construct a tree ——构造树

Misha walked through the snowy forest and he was so fascinated by the trees to decide to draw his own tree!

Misha would like to construct a rooted tree with n vertices, indexed from 1 to n, where the root has index 1. Every other vertex has a parent pi, and i is called a child of vertex pi. Vertex u belongs to the subtree of vertex v iff v is reachable from u while iterating over the parents (u, pu, ppu, …). Clearly, v belongs to its own subtree, and the number of vertices in the subtree is called the size of the subtree. Misha is only interested in trees where every vertex belongs to the subtree of vertex 1.

Below there is a tree with 6 vertices. The subtree of vertex 2 contains vertices 2, 3, 4, 5. Hence the size of its subtree is 4.
在这里插入图片描述

The branching coefficient of the tree is defined as the maximum number of children in any vertex. For example, for the tree above the branching coefficient equals 2. Your task is to construct a tree with n vertices such that the sum of the subtree sizes for all vertices equals s, and the branching coefficient is minimum possible.

Input
The only input line contains two integers n and s — the number of vertices in the tree and the desired sum of the subtree sizes (2≤n≤105; 1≤s≤1010).

Output
If the required tree does not exist, output «No». Otherwise output «Yes» on the first line, and in the next one output integers p2, p3, …, pn, where pi denotes the parent of vertex i.

Examples
inputCopy
3 5
outputCopy
Yes
1 1
inputCopy
4 42
outputCopy
No
inputCopy
6 15
outputCopy
Yes
1 2 3 1 5

题意:

给你一个数n和一个数s,让你用n个点构造一棵树,使得所有点的子树的大小累加起来等于s,且这棵树的最大分叉最小

题解:

一旦出现最大值最小的,基本是二分,我们二分最大分叉,检查这个分叉下子树大小累加最小的构造情况是否大于s,如果不是,那么这个分叉数就可能是答案,之后我们先将这个树设为一个链,因为这个时候值最大,之后如果这棵树的值大于s,那么就把最下面的点往上移,首先如果当前的点能够移到的最顶端所减少的数小于sum-s,那么就直接当前能够移到的最顶端的数的数量加1,当前点的dep的数量-1,否则就移到i-(sum-s)的位置。
确定好每一层有多少个点之后,我们就可以枚举每一个点所在的位置,用一个vector来记当前层有哪些数。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
ll n,s;
int check(ll mid)
{
    ll res=n,num=1,sum=0,dep=1;
    while(res)
    {
        sum+=min(num,res)*dep;
        if(sum>s)
            return 0;
        res-=min(num,res);
        num*=mid;
        dep++;
    }
    return 1;
}
int fa[N],dep[N];
vector<int>vec[N];
int main()
{
    scanf("%lld%lld",&n,&s);
    if(n+n-1>s||(n+1)*n/2<s)
        return 0*printf("No\n");
    ll l=1,r=n,mid,ans=1;
    while(r>=l)
    {
        mid=l+r>>1;
        if(check(mid))
            r=mid-1,ans=mid;
        else
            l=mid+1;
    }
    printf("Yes\n");
    ll sum=(n+1)*n/2,head=2;
    for(int i=1;i<=n;i++)
        fa[i]=i-1,dep[i]=1;
    for(int i=n;i>=2;i--)
    {
        if(sum==s)
            break;
        if(dep[head]>=dep[head-1]*ans)
            head++;
        if(sum-s>=i-head)
        {
            dep[head]++,dep[i]--;
            sum-=(i-head);
        }
        else
        {
            dep[i-(sum-s)]++;
            dep[i]--;
            sum=s;
        }
    }
    vec[1].push_back(1);
    head=1;
    int now=2;
    while(now<=n)
    {
        for(int j=0;j<dep[head+1]&&now<=n;j++)
        {
            printf("%d ",vec[head][j/ans]);
            vec[head+1].push_back(now++);
        }
        head++;
    }
    printf("\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/88969778