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