Loading

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;
}

posted @ 2021-10-18 11:45  Dita  阅读(24)  评论(0编辑  收藏  举报