CF1283F DIY Garland
solution
-
根节点一定是第一个点。
-
越后第一次出现的点深度一定更深。而没有出现的点就一定是叶子节点了。
记一下每一个点的出现个数,可以理解为入度。没有出现过的,即是叶子节点,我们把他们扔进一个小根堆里
然后我们考虑配对。
一个数的出现次数一定是他的儿子个数,那我们就好连边了。从后往前遍历 \(a\) 数组,每一个数和堆顶连边,同时该点 \(ind[a[i]]\) 如果 \(ind[a[i]]\) 为零了,就加入堆里。这样循环 \(n-1\)次,即可构造出一组解。这样一定是从下到上连边的。
/*
work by: Ariel_
Knowledge:
Time:
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = 2e5 + 5;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int ind[MAXN], n, a[MAXN];
priority_queue<int, vector<int>, greater<int> >q;
int main(){
n = read();
for (int i = 1; i < n; i++) a[i] = read(), ind[a[i]]++;
printf("%d\n", a[1]);
for (int i = 1; i <= n; i++) if(!ind[i]) q.push(i);
for (int i = n - 1; i >= 1; i--) {
int u = q.top(); q.pop();
printf("%d %d\n", u, a[i]);
ind[a[i]]--;
if(!ind[a[i]]) q.push(a[i]);
}
return 0;
}

浙公网安备 33010602011771号