• CF 1098 C. Construct a tree


    题目大意:

    对于一棵树,我们定义“分支系数”为子节点最多的节点的子结点个数。现给出结点个数 $n$ 、所有节点的子树大小之和 $s$ ,同时规定符合条件的树的根节点必须是 $1$ 。请你判断是否存在一棵符合条件的树。如果存在,请你输出“分支系数”最小的符合条件的树。输出方式是,你需要分别输出编号为 $2$ 的节点~编号为 $n$  的节点的父节点。

    思路:
    考虑如果没有分支系数最小的限制,那么一条链的时候答案为 $i*(i+1)/2$ ,每次把最底层的叶子向上移动一层,答案就减 $1$ ,可以构造出一组解,但是答案不一定优。

    显然,分支系数越大节点的子树大小之和上界越小。考虑二分出一个答案可行答案,之后在二分出的答案的基础上把节点贪心的往上层移动,可以构造出一组合法的解。

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1e5+5;
    vector<int> v[N];
    int n,fa[N],sz[N];LL s,sum,res;
    il int read(){
       int x,f=1;char ch;
       _(!)ch=='-'?f=-1:f;x=ch^48;
       _()x=(x<<1)+(x<<3)+(ch^48);
       return f*x;
    }
    il bool pd(int x){
        res=0;int t=n;LL now=1;int l=1;
        while(t){
            if(t>=now){
                res+=now*l;t-=now;
            }
            else{
                res+=t*l;t=0;
            }
            now*=x;l++;
        }
        return res<=s;
    }
    int main()
    {
        n=read();scanf("%I64d",&s);
        if(s<n*2-1||1ll*n*(n+1)/2<s){puts("No");return 0;}
        if(1ll*n*(n+1)/2==s){
            puts("Yes");
            for(int i=1;i<n;i++)printf("%d ",i);
            return 0;
        }
        int l=1,r=n,ret=n;
        while(l<=r){
            int mid=(l+r)>>1;
            if(pd(mid))r=mid-1,ret=mid;
            else l=mid+1;
        }
        for(int i=1;i<=n;i++)v[i].push_back(i);
        s=1ll*n*(n+1)/2-s;
        for(int i=2;i<=n;i++)fa[i]=i-1,sz[i-1]=1;
        int now=1;
        for(int i=n;i;i--){
            while(v[now].size()==0)now++;
            if(i-now-1<=s){
                s-=(i-now-1);
                int k=v[now].size()-1;
                int d=v[now][k];sz[d]++;
                if(sz[d]==ret)v[now].pop_back();
                v[now+1].push_back(i);
                sz[fa[i]]--;fa[i]=d;
            }
            else{
                int k=i-s-1;
                int x=v[k][0];
                fa[i]=x;s=0;
            }
            if(s==0)break;
        }
        //printf("!!!%d ",ret);
        puts("Yes");
        for(int i=2;i<=n;i++)printf("%d ",fa[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    统计次数
    使用正则消除行号
    【收集】sql查询统计,周,月,年
    ASP.NET脚本过滤-防止跨站脚本攻击(收集别人的)
    win10环境下jdk1.8+Android Developer Tools Build: v22.3.0-887826的问题
    关于虚拟机的问题解决(转自豆瓣)
    工作
    numpy学习
    deepin Python pycharm安装
    pymysql连接和操作Mysql数据库
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10544622.html
Copyright © 2020-2023  润新知