CF746G New Roads
题意
给你一棵 t t t层的树,第 i i i层有 a [ i ] a[i] a[i]个节点,最后需要有 k k k个叶子结点,让你构造出一棵符合条件的树。
解题思路
我们可以先构造出 t t t层,每层只有一个节点,父亲是上一层的节点。那么显然此时剩余的节点数为 n − t n-t n−t。剩余所需的非叶子节点的数量为 n − t − k n-t-k n−t−k。于是我们可以逐层插入节点,并对这些节点分类讨论。设此时已经插入到第 i i i层的第 j j j个点。如果此时还需要非叶子节点,那么它的父亲就可以是第 i − 1 i-1 i−1层的第 j j j个,这样它的父亲就变为了非叶子节点;反之,如果不需要非叶子节点,直接用上一层的第一个节点当做它的父亲,那么上一层当前位置的节点就成为了叶子结点。
对于无解的判断,无非就是最末层的节点数大于 k k k,因为最后一层的节点必定是叶子结点。或者在构造完之后还需要非叶子节点,但此时已经没有可以构造的叶子节点了。
代码
#include <bits/stdc++.h>
using namespace std;
int n, t, k, cnt;
vector<int> v[200005];
int a[200005], fa[200005];
int main()
{
cin >> n >> t >> k;
a[0] = 1;
for(int i = 1; i <= t; i++){
scanf("%d", &a[i]);
}
if(a[t]>k || n-t<k){
puts("-1");
return 0;
}
for(int i = 0; i <= t; i++){
for(int j = 1; j <= a[i]; j++)
v[i].push_back(++cnt);
}
for(int i = 0; i < a[1]; i++){
fa[v[1][i]] = 1;
}
for(int i = 2; i <= t; i++){
fa[v[i][0]] = v[i-1][0];
}
int l = n-t-k;
for(int i = 2; i <= t; i++){
for(int j = 1; j < a[i]; j++){
if(l && j < a[i-1]){
fa[v[i][j]] = v[i-1][j];
l--;
}
else{
fa[v[i][j]] = v[i-1][0];
}
}
}
if(l){
puts("-1");
return 0;
}
cout << n << endl;
for(int i = 2; i <= n; i++){
printf("%d %d\n", fa[i], i);
}
return 0;
}