【CF1311E】Construct the Binary Tree【增量构造】【复杂度证明】
題意:給定nnn和ddd,構造或判斷無法構造一棵二叉樹使得所有點的深度(定義為到根距離)之和為ddd。
n,d≤5000n,d\leq 5000n,d≤5000
顯然可以算出有解的ddd的下界和上界,分別是完全二叉樹和鏈的情況。下面會證明在這個范圍內一定有解。
考慮增量,先構造出一條鏈,每次選一個葉結點接到深度小111的位置。
具體實現可以按編號暴力枚舉葉結點,然后暴力枚舉新位置的父親(即深度小222且兒子數<2<2<2)。如果找不到,因為它的祖先都遍歷過,感性理解,這個葉結點上面都放滿了,以后不可能再用,打上標記,下次增量的時候不訪問。
一棵二叉樹是完全二叉樹,當且僅當所有倒數第三深的點都已經有兩個兒子。所以不是完全二叉樹時可以按上面的方法增量。
復雜度看似是O(n(n2?d))O(n(n^2-d))O(n(n2?d)),但實際上ddd小于下界時可以直接輸出NO
顯然下界是O(nlog?n)O(n\log n)O(nlogn)的,也就是說只需要考慮nlog?n<dn\log n<dnlogn<d
變換得n<dlog?nn<\fracze8trgl8bvbq{\log n}n<lognd?
那么復雜度不劣于O((dlog?n)3)O((\fracze8trgl8bvbq{\log n})^3)O((lognd?)3)
當d=5000d=5000d=5000,nnn最小只能到根號級別
加上算法復雜度不滿,可以通過
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #define MAXN 5005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } int fa[MAXN],cnt[MAXN],sum[MAXN],dep[MAXN],bad[MAXN]; int main() {sum[1]=1;for (int i=2;i<MAXN;i++) sum[i]=i+sum[i/2]+sum[i-i/2-1];for (int i=1;i<MAXN;i++) sum[i]-=i;for (int T=read();T;T--){int n,d;n=read(),d=read();int cur=n*(n-1)/2;if (d<sum[n]||d>cur) {puts("NO");continue;}fa[1]=0;for (int i=2;i<=n;i++) fa[i]=i-1;for (int i=1;i<n;i++) cnt[i]=1;cnt[n]=0;for (int i=1;i<=n;i++) bad[i]=0,dep[i]=i-1;while (cur>d){int u;for (u=1;u<=n;u++)if (!cnt[u]&&!bad[u])break;bad[u]=1;for (int p=1;p<=n;p++)if (cnt[p]<2&&dep[u]-dep[p]==2){--cnt[fa[u]],fa[u]=p;dep[u]=dep[p]+1,++cnt[p];bad[u]=0,--cur;break;}}puts("YES");for (int i=2;i<=n;i++) printf("%d%c",fa[i]," \n"[i==n]);}return 0; }總結
以上是生活随笔為你收集整理的【CF1311E】Construct the Binary Tree【增量构造】【复杂度证明】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 食源性疾病是什么
- 下一篇: 【CF1338C】Perfect Tri