cppAcademy
FROM LEARNING TO COMPETING

Real problems.
Your next challenge.

Explore the Group C Olympiad and Autumn Tournament archive.
Choose a topic. Find a challenge. Build your solution.

274 tasks: 213 from the Municipal, Regional, and National Olympiad rounds (2009–2026), 57 Autumn Tournament tasks (2007–2025), and 4 previously featured problems. 207 tasks have independently written English summaries, analyses, and C++17 solutions; the remaining entries link to Arena. Difficulty labels are learning estimates, not official ratings. Special formats and source clarifications are explained on affected tasks.
GROUP C2011 · MediumTrees and DFS preorder

Lexicographically Smallest Company Seating

Autumn Tournament (2011)

Submission name: company.cpp

Problem summary

Arrange a rooted company hierarchy in one row. Every manager must appear before every direct subordinate, and every rooted subtree must occupy a contiguous block. Output the lexicographically smallest valid employee order. Employee 1 is the root.

Source clarification. Arena lists this problem in the 2011 Group C Autumn catalogue, but the linked PDF header says National Olympiad, 24 January 2010. The archive retains Arena’s listing/year and solves the linked company-seating statement.

Input

N followed by N−1 manager/subordinate pairs.

Output

The lexicographically smallest valid permutation of employees 1..N.

Constraints

1 ≤ N ≤ 200000; the input is a rooted tree with root 1.

Worked example

Original statement sample.

Input

6
1 2
2 5
4 3
1 4
4 6

Output

1 2 5 4 3 6

Solution analysis

  1. The contiguous-team condition means that, after placing a manager, each child subtree must be placed as one entire block. Consequently a valid arrangement is a DFS preorder: print the node, then recursively print its child subtrees.
  2. Two child blocks begin with different child IDs. To obtain the smallest lexicographic sequence, process these child roots in increasing order. Apply the same rule inside every subtree. It is incorrect to use a global smallest-available employee queue: that can split a team block.
  3. For the sample, root 1 has child roots 2 and 4, so the whole subtree of 2 precedes the subtree of 4. This produces 1,2,5,4,3,6 even though employee 3 is smaller than 5. Use an explicit stack rather than recursive function calls so a chain of 200000 employees does not overflow the call stack.

Why it works

Every valid order starts with its root and then concatenates whole child-subtree blocks. Since each such block starts with its child root, any inversion of two child roots can be swapped to strictly improve lexicographic order without violating either constraint. Sorting children and applying the same argument recursively is therefore optimal.

Complexity: O(N log N) worst-case time and O(N) space. Sorting all child lists costs at most O(N log N); iterative traversal visits each vertex and edge once.

Watch out. Finish an entire child subtree before visiting the next sibling. Push sorted children onto a LIFO stack in reverse order so the smallest is popped first. Do not use recursive DFS without considering maximum tree depth.

Commented C++17 solution

An independently written complete program with standard headers.

#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin>>n;
    vector<vector<int>>children(n+1);
    for(int edge=0;edge<n-1;edge++){
        int manager;
        int employee;
        cin>>manager>>employee;
        children[manager].push_back(employee);
    }
    for(auto&list:children){
        sort(list.begin(),list.end());
    }
    vector<int>pending={1};
    bool first=true;
    while(!pending.empty()){
        int employee=pending.back();
        pending.pop_back();
        if(!first){
            cout<<' ';
        }
        cout<<employee;
        first=false;
        // Reverse insertion preserves increasing child order when popping.
        for(auto it=children[employee].rbegin();it!=children[employee].rend();++it){
            pending.push_back(*it);
        }
    }
    cout<<'\n';
}

Source: Arena Olimpiici ↗