Codeforces 1098C Construct a tree
首先题意大致为给出n,s,构造节点数为n,所有点的深度之和为s的树,并且要求分支系数尽可能小,分支系数为儿子个数的最大值
手模样例发现分支系数k越大,sm(构造方案的深度之和)越小
首先判断无解就是不在2*n-1(菊花图)~(n+1)*n/2(链)的范围内
其次由于s关于k的单调性,可以二分k,同一个k,当树是完全k叉树时,得到的sm最小,二分出使sm<=s的最小k
然后考虑在这个完全二叉树的基础上变成最终答案
维护每层的最右侧的节点,这是一条链,把v放到这条链的u上,且dep(u)>=dep(v),则能使sm变成sm+dep(u)-dep(v)+1
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 #define int long long 5 const int MAXN=1e5+17; 6 int n;LL s; 7 vector<int >v[MAXN]; 8 int p[MAXN],tot; 9 int mxdep; 10 LL lres=0; 11 inline bool check(int x){ 12 for(int i=1;i<=n;++i)v[i].clear(); 13 int tmp=n-1; 14 LL res=1,base=2; 15 v[1].clear(); 16 v[1].push_back(1); 17 p[tot=1]=0; 18 while(tmp){ 19 v[base].clear(); 20 for(int j=0;tmp&&j<v[base-1].size();++j){ 21 int y=v[base-1][j]; 22 for(int k=0;tmp&&k<x;++k) 23 p[++tot]=y,tmp--,res+=base,v[base].push_back(tot); 24 } 25 base++; 26 } 27 mxdep=base-1; 28 lres=res; 29 return res<=s; 30 } 31 signed main(){ 32 scanf("%lld%lld",&n,&s); 33 if(s<2LL*n-1||s>(n+1LL)*n/2LL)puts("No"),exit(0); 34 puts("Yes"); 35 int l=1,r=n-1; 36 while(r-l>1){ 37 int mid=l+r>>1; 38 if(check(mid))r=mid; 39 else l=mid; 40 } 41 int ans=0; 42 if(check(l))ans=l; 43 else check(r),ans=r; 44 // cout<<ans<<endl; 45 46 47 int js=s-lres; 48 for(int i=mxdep;js&&i>1;--i){ 49 for(int j=v[i].size()-1;js&&j>0;--j){ 50 int pp=i,y=v[i][j]; 51 v[i].pop_back(); 52 if(js-(mxdep-i+1)>=0)pp=mxdep; 53 else pp=js+i-1; 54 p[y]=v[pp][0]; 55 v[pp+1].push_back(y); 56 mxdep=max(mxdep,pp+1); 57 js-=(pp-i+1); 58 } 59 } 60 61 for(int i=2;i<=n;++i)printf("%lld%c",p[i],i==n?'\n':' '); 62 return 0; 63 } 64 /* 65 66 71 1329 67 68 */